162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/signal.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/netdevice.h>
1062306a36Sopenharmony_ci#include <linux/etherdevice.h>
1162306a36Sopenharmony_ci#include <linux/mii.h>
1262306a36Sopenharmony_ci#include <linux/ethtool.h>
1362306a36Sopenharmony_ci#include <linux/usb.h>
1462306a36Sopenharmony_ci#include <linux/crc32.h>
1562306a36Sopenharmony_ci#include <linux/if_vlan.h>
1662306a36Sopenharmony_ci#include <linux/uaccess.h>
1762306a36Sopenharmony_ci#include <linux/list.h>
1862306a36Sopenharmony_ci#include <linux/ip.h>
1962306a36Sopenharmony_ci#include <linux/ipv6.h>
2062306a36Sopenharmony_ci#include <net/ip6_checksum.h>
2162306a36Sopenharmony_ci#include <uapi/linux/mdio.h>
2262306a36Sopenharmony_ci#include <linux/mdio.h>
2362306a36Sopenharmony_ci#include <linux/usb/cdc.h>
2462306a36Sopenharmony_ci#include <linux/suspend.h>
2562306a36Sopenharmony_ci#include <linux/atomic.h>
2662306a36Sopenharmony_ci#include <linux/acpi.h>
2762306a36Sopenharmony_ci#include <linux/firmware.h>
2862306a36Sopenharmony_ci#include <crypto/hash.h>
2962306a36Sopenharmony_ci#include <linux/usb/r8152.h>
3062306a36Sopenharmony_ci#include <net/gso.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Information for net-next */
3362306a36Sopenharmony_ci#define NETNEXT_VERSION		"12"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* Information for net */
3662306a36Sopenharmony_ci#define NET_VERSION		"13"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define DRIVER_VERSION		"v1." NETNEXT_VERSION "." NET_VERSION
3962306a36Sopenharmony_ci#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
4062306a36Sopenharmony_ci#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
4162306a36Sopenharmony_ci#define MODULENAME "r8152"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define R8152_PHY_ID		32
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define PLA_IDR			0xc000
4662306a36Sopenharmony_ci#define PLA_RCR			0xc010
4762306a36Sopenharmony_ci#define PLA_RCR1		0xc012
4862306a36Sopenharmony_ci#define PLA_RMS			0xc016
4962306a36Sopenharmony_ci#define PLA_RXFIFO_CTRL0	0xc0a0
5062306a36Sopenharmony_ci#define PLA_RXFIFO_FULL		0xc0a2
5162306a36Sopenharmony_ci#define PLA_RXFIFO_CTRL1	0xc0a4
5262306a36Sopenharmony_ci#define PLA_RX_FIFO_FULL	0xc0a6
5362306a36Sopenharmony_ci#define PLA_RXFIFO_CTRL2	0xc0a8
5462306a36Sopenharmony_ci#define PLA_RX_FIFO_EMPTY	0xc0aa
5562306a36Sopenharmony_ci#define PLA_DMY_REG0		0xc0b0
5662306a36Sopenharmony_ci#define PLA_FMC			0xc0b4
5762306a36Sopenharmony_ci#define PLA_CFG_WOL		0xc0b6
5862306a36Sopenharmony_ci#define PLA_TEREDO_CFG		0xc0bc
5962306a36Sopenharmony_ci#define PLA_TEREDO_WAKE_BASE	0xc0c4
6062306a36Sopenharmony_ci#define PLA_MAR			0xcd00
6162306a36Sopenharmony_ci#define PLA_BACKUP		0xd000
6262306a36Sopenharmony_ci#define PLA_BDC_CR		0xd1a0
6362306a36Sopenharmony_ci#define PLA_TEREDO_TIMER	0xd2cc
6462306a36Sopenharmony_ci#define PLA_REALWOW_TIMER	0xd2e8
6562306a36Sopenharmony_ci#define PLA_UPHY_TIMER		0xd388
6662306a36Sopenharmony_ci#define PLA_SUSPEND_FLAG	0xd38a
6762306a36Sopenharmony_ci#define PLA_INDICATE_FALG	0xd38c
6862306a36Sopenharmony_ci#define PLA_MACDBG_PRE		0xd38c	/* RTL_VER_04 only */
6962306a36Sopenharmony_ci#define PLA_MACDBG_POST		0xd38e	/* RTL_VER_04 only */
7062306a36Sopenharmony_ci#define PLA_EXTRA_STATUS	0xd398
7162306a36Sopenharmony_ci#define PLA_GPHY_CTRL		0xd3ae
7262306a36Sopenharmony_ci#define PLA_POL_GPIO_CTRL	0xdc6a
7362306a36Sopenharmony_ci#define PLA_EFUSE_DATA		0xdd00
7462306a36Sopenharmony_ci#define PLA_EFUSE_CMD		0xdd02
7562306a36Sopenharmony_ci#define PLA_LEDSEL		0xdd90
7662306a36Sopenharmony_ci#define PLA_LED_FEATURE		0xdd92
7762306a36Sopenharmony_ci#define PLA_PHYAR		0xde00
7862306a36Sopenharmony_ci#define PLA_BOOT_CTRL		0xe004
7962306a36Sopenharmony_ci#define PLA_LWAKE_CTRL_REG	0xe007
8062306a36Sopenharmony_ci#define PLA_GPHY_INTR_IMR	0xe022
8162306a36Sopenharmony_ci#define PLA_EEE_CR		0xe040
8262306a36Sopenharmony_ci#define PLA_EEE_TXTWSYS		0xe04c
8362306a36Sopenharmony_ci#define PLA_EEE_TXTWSYS_2P5G	0xe058
8462306a36Sopenharmony_ci#define PLA_EEEP_CR		0xe080
8562306a36Sopenharmony_ci#define PLA_MAC_PWR_CTRL	0xe0c0
8662306a36Sopenharmony_ci#define PLA_MAC_PWR_CTRL2	0xe0ca
8762306a36Sopenharmony_ci#define PLA_MAC_PWR_CTRL3	0xe0cc
8862306a36Sopenharmony_ci#define PLA_MAC_PWR_CTRL4	0xe0ce
8962306a36Sopenharmony_ci#define PLA_WDT6_CTRL		0xe428
9062306a36Sopenharmony_ci#define PLA_TCR0		0xe610
9162306a36Sopenharmony_ci#define PLA_TCR1		0xe612
9262306a36Sopenharmony_ci#define PLA_MTPS		0xe615
9362306a36Sopenharmony_ci#define PLA_TXFIFO_CTRL		0xe618
9462306a36Sopenharmony_ci#define PLA_TXFIFO_FULL		0xe61a
9562306a36Sopenharmony_ci#define PLA_RSTTALLY		0xe800
9662306a36Sopenharmony_ci#define PLA_CR			0xe813
9762306a36Sopenharmony_ci#define PLA_CRWECR		0xe81c
9862306a36Sopenharmony_ci#define PLA_CONFIG12		0xe81e	/* CONFIG1, CONFIG2 */
9962306a36Sopenharmony_ci#define PLA_CONFIG34		0xe820	/* CONFIG3, CONFIG4 */
10062306a36Sopenharmony_ci#define PLA_CONFIG5		0xe822
10162306a36Sopenharmony_ci#define PLA_PHY_PWR		0xe84c
10262306a36Sopenharmony_ci#define PLA_OOB_CTRL		0xe84f
10362306a36Sopenharmony_ci#define PLA_CPCR		0xe854
10462306a36Sopenharmony_ci#define PLA_MISC_0		0xe858
10562306a36Sopenharmony_ci#define PLA_MISC_1		0xe85a
10662306a36Sopenharmony_ci#define PLA_OCP_GPHY_BASE	0xe86c
10762306a36Sopenharmony_ci#define PLA_TALLYCNT		0xe890
10862306a36Sopenharmony_ci#define PLA_SFF_STS_7		0xe8de
10962306a36Sopenharmony_ci#define PLA_PHYSTATUS		0xe908
11062306a36Sopenharmony_ci#define PLA_CONFIG6		0xe90a /* CONFIG6 */
11162306a36Sopenharmony_ci#define PLA_USB_CFG		0xe952
11262306a36Sopenharmony_ci#define PLA_BP_BA		0xfc26
11362306a36Sopenharmony_ci#define PLA_BP_0		0xfc28
11462306a36Sopenharmony_ci#define PLA_BP_1		0xfc2a
11562306a36Sopenharmony_ci#define PLA_BP_2		0xfc2c
11662306a36Sopenharmony_ci#define PLA_BP_3		0xfc2e
11762306a36Sopenharmony_ci#define PLA_BP_4		0xfc30
11862306a36Sopenharmony_ci#define PLA_BP_5		0xfc32
11962306a36Sopenharmony_ci#define PLA_BP_6		0xfc34
12062306a36Sopenharmony_ci#define PLA_BP_7		0xfc36
12162306a36Sopenharmony_ci#define PLA_BP_EN		0xfc38
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define USB_USB2PHY		0xb41e
12462306a36Sopenharmony_ci#define USB_SSPHYLINK1		0xb426
12562306a36Sopenharmony_ci#define USB_SSPHYLINK2		0xb428
12662306a36Sopenharmony_ci#define USB_L1_CTRL		0xb45e
12762306a36Sopenharmony_ci#define USB_U2P3_CTRL		0xb460
12862306a36Sopenharmony_ci#define USB_CSR_DUMMY1		0xb464
12962306a36Sopenharmony_ci#define USB_CSR_DUMMY2		0xb466
13062306a36Sopenharmony_ci#define USB_DEV_STAT		0xb808
13162306a36Sopenharmony_ci#define USB_CONNECT_TIMER	0xcbf8
13262306a36Sopenharmony_ci#define USB_MSC_TIMER		0xcbfc
13362306a36Sopenharmony_ci#define USB_BURST_SIZE		0xcfc0
13462306a36Sopenharmony_ci#define USB_FW_FIX_EN0		0xcfca
13562306a36Sopenharmony_ci#define USB_FW_FIX_EN1		0xcfcc
13662306a36Sopenharmony_ci#define USB_LPM_CONFIG		0xcfd8
13762306a36Sopenharmony_ci#define USB_ECM_OPTION		0xcfee
13862306a36Sopenharmony_ci#define USB_CSTMR		0xcfef	/* RTL8153A */
13962306a36Sopenharmony_ci#define USB_MISC_2		0xcfff
14062306a36Sopenharmony_ci#define USB_ECM_OP		0xd26b
14162306a36Sopenharmony_ci#define USB_GPHY_CTRL		0xd284
14262306a36Sopenharmony_ci#define USB_SPEED_OPTION	0xd32a
14362306a36Sopenharmony_ci#define USB_FW_CTRL		0xd334	/* RTL8153B */
14462306a36Sopenharmony_ci#define USB_FC_TIMER		0xd340
14562306a36Sopenharmony_ci#define USB_USB_CTRL		0xd406
14662306a36Sopenharmony_ci#define USB_PHY_CTRL		0xd408
14762306a36Sopenharmony_ci#define USB_TX_AGG		0xd40a
14862306a36Sopenharmony_ci#define USB_RX_BUF_TH		0xd40c
14962306a36Sopenharmony_ci#define USB_USB_TIMER		0xd428
15062306a36Sopenharmony_ci#define USB_RX_EARLY_TIMEOUT	0xd42c
15162306a36Sopenharmony_ci#define USB_RX_EARLY_SIZE	0xd42e
15262306a36Sopenharmony_ci#define USB_PM_CTRL_STATUS	0xd432	/* RTL8153A */
15362306a36Sopenharmony_ci#define USB_RX_EXTRA_AGGR_TMR	0xd432	/* RTL8153B */
15462306a36Sopenharmony_ci#define USB_TX_DMA		0xd434
15562306a36Sopenharmony_ci#define USB_UPT_RXDMA_OWN	0xd437
15662306a36Sopenharmony_ci#define USB_UPHY3_MDCMDIO	0xd480
15762306a36Sopenharmony_ci#define USB_TOLERANCE		0xd490
15862306a36Sopenharmony_ci#define USB_LPM_CTRL		0xd41a
15962306a36Sopenharmony_ci#define USB_BMU_RESET		0xd4b0
16062306a36Sopenharmony_ci#define USB_BMU_CONFIG		0xd4b4
16162306a36Sopenharmony_ci#define USB_U1U2_TIMER		0xd4da
16262306a36Sopenharmony_ci#define USB_FW_TASK		0xd4e8	/* RTL8153B */
16362306a36Sopenharmony_ci#define USB_RX_AGGR_NUM		0xd4ee
16462306a36Sopenharmony_ci#define USB_UPS_CTRL		0xd800
16562306a36Sopenharmony_ci#define USB_POWER_CUT		0xd80a
16662306a36Sopenharmony_ci#define USB_MISC_0		0xd81a
16762306a36Sopenharmony_ci#define USB_MISC_1		0xd81f
16862306a36Sopenharmony_ci#define USB_AFE_CTRL2		0xd824
16962306a36Sopenharmony_ci#define USB_UPHY_XTAL		0xd826
17062306a36Sopenharmony_ci#define USB_UPS_CFG		0xd842
17162306a36Sopenharmony_ci#define USB_UPS_FLAGS		0xd848
17262306a36Sopenharmony_ci#define USB_WDT1_CTRL		0xe404
17362306a36Sopenharmony_ci#define USB_WDT11_CTRL		0xe43c
17462306a36Sopenharmony_ci#define USB_BP_BA		PLA_BP_BA
17562306a36Sopenharmony_ci#define USB_BP_0		PLA_BP_0
17662306a36Sopenharmony_ci#define USB_BP_1		PLA_BP_1
17762306a36Sopenharmony_ci#define USB_BP_2		PLA_BP_2
17862306a36Sopenharmony_ci#define USB_BP_3		PLA_BP_3
17962306a36Sopenharmony_ci#define USB_BP_4		PLA_BP_4
18062306a36Sopenharmony_ci#define USB_BP_5		PLA_BP_5
18162306a36Sopenharmony_ci#define USB_BP_6		PLA_BP_6
18262306a36Sopenharmony_ci#define USB_BP_7		PLA_BP_7
18362306a36Sopenharmony_ci#define USB_BP_EN		PLA_BP_EN	/* RTL8153A */
18462306a36Sopenharmony_ci#define USB_BP_8		0xfc38		/* RTL8153B */
18562306a36Sopenharmony_ci#define USB_BP_9		0xfc3a
18662306a36Sopenharmony_ci#define USB_BP_10		0xfc3c
18762306a36Sopenharmony_ci#define USB_BP_11		0xfc3e
18862306a36Sopenharmony_ci#define USB_BP_12		0xfc40
18962306a36Sopenharmony_ci#define USB_BP_13		0xfc42
19062306a36Sopenharmony_ci#define USB_BP_14		0xfc44
19162306a36Sopenharmony_ci#define USB_BP_15		0xfc46
19262306a36Sopenharmony_ci#define USB_BP2_EN		0xfc48
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/* OCP Registers */
19562306a36Sopenharmony_ci#define OCP_ALDPS_CONFIG	0x2010
19662306a36Sopenharmony_ci#define OCP_EEE_CONFIG1		0x2080
19762306a36Sopenharmony_ci#define OCP_EEE_CONFIG2		0x2092
19862306a36Sopenharmony_ci#define OCP_EEE_CONFIG3		0x2094
19962306a36Sopenharmony_ci#define OCP_BASE_MII		0xa400
20062306a36Sopenharmony_ci#define OCP_EEE_AR		0xa41a
20162306a36Sopenharmony_ci#define OCP_EEE_DATA		0xa41c
20262306a36Sopenharmony_ci#define OCP_PHY_STATUS		0xa420
20362306a36Sopenharmony_ci#define OCP_INTR_EN		0xa424
20462306a36Sopenharmony_ci#define OCP_NCTL_CFG		0xa42c
20562306a36Sopenharmony_ci#define OCP_POWER_CFG		0xa430
20662306a36Sopenharmony_ci#define OCP_EEE_CFG		0xa432
20762306a36Sopenharmony_ci#define OCP_SRAM_ADDR		0xa436
20862306a36Sopenharmony_ci#define OCP_SRAM_DATA		0xa438
20962306a36Sopenharmony_ci#define OCP_DOWN_SPEED		0xa442
21062306a36Sopenharmony_ci#define OCP_EEE_ABLE		0xa5c4
21162306a36Sopenharmony_ci#define OCP_EEE_ADV		0xa5d0
21262306a36Sopenharmony_ci#define OCP_EEE_LPABLE		0xa5d2
21362306a36Sopenharmony_ci#define OCP_10GBT_CTRL		0xa5d4
21462306a36Sopenharmony_ci#define OCP_10GBT_STAT		0xa5d6
21562306a36Sopenharmony_ci#define OCP_EEE_ADV2		0xa6d4
21662306a36Sopenharmony_ci#define OCP_PHY_STATE		0xa708		/* nway state for 8153 */
21762306a36Sopenharmony_ci#define OCP_PHY_PATCH_STAT	0xb800
21862306a36Sopenharmony_ci#define OCP_PHY_PATCH_CMD	0xb820
21962306a36Sopenharmony_ci#define OCP_PHY_LOCK		0xb82e
22062306a36Sopenharmony_ci#define OCP_ADC_IOFFSET		0xbcfc
22162306a36Sopenharmony_ci#define OCP_ADC_CFG		0xbc06
22262306a36Sopenharmony_ci#define OCP_SYSCLK_CFG		0xc416
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/* SRAM Register */
22562306a36Sopenharmony_ci#define SRAM_GREEN_CFG		0x8011
22662306a36Sopenharmony_ci#define SRAM_LPF_CFG		0x8012
22762306a36Sopenharmony_ci#define SRAM_GPHY_FW_VER	0x801e
22862306a36Sopenharmony_ci#define SRAM_10M_AMP1		0x8080
22962306a36Sopenharmony_ci#define SRAM_10M_AMP2		0x8082
23062306a36Sopenharmony_ci#define SRAM_IMPEDANCE		0x8084
23162306a36Sopenharmony_ci#define SRAM_PHY_LOCK		0xb82e
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* PLA_RCR */
23462306a36Sopenharmony_ci#define RCR_AAP			0x00000001
23562306a36Sopenharmony_ci#define RCR_APM			0x00000002
23662306a36Sopenharmony_ci#define RCR_AM			0x00000004
23762306a36Sopenharmony_ci#define RCR_AB			0x00000008
23862306a36Sopenharmony_ci#define RCR_ACPT_ALL		(RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
23962306a36Sopenharmony_ci#define SLOT_EN			BIT(11)
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/* PLA_RCR1 */
24262306a36Sopenharmony_ci#define OUTER_VLAN		BIT(7)
24362306a36Sopenharmony_ci#define INNER_VLAN		BIT(6)
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/* PLA_RXFIFO_CTRL0 */
24662306a36Sopenharmony_ci#define RXFIFO_THR1_NORMAL	0x00080002
24762306a36Sopenharmony_ci#define RXFIFO_THR1_OOB		0x01800003
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/* PLA_RXFIFO_FULL */
25062306a36Sopenharmony_ci#define RXFIFO_FULL_MASK	0xfff
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/* PLA_RXFIFO_CTRL1 */
25362306a36Sopenharmony_ci#define RXFIFO_THR2_FULL	0x00000060
25462306a36Sopenharmony_ci#define RXFIFO_THR2_HIGH	0x00000038
25562306a36Sopenharmony_ci#define RXFIFO_THR2_OOB		0x0000004a
25662306a36Sopenharmony_ci#define RXFIFO_THR2_NORMAL	0x00a0
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/* PLA_RXFIFO_CTRL2 */
25962306a36Sopenharmony_ci#define RXFIFO_THR3_FULL	0x00000078
26062306a36Sopenharmony_ci#define RXFIFO_THR3_HIGH	0x00000048
26162306a36Sopenharmony_ci#define RXFIFO_THR3_OOB		0x0000005a
26262306a36Sopenharmony_ci#define RXFIFO_THR3_NORMAL	0x0110
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/* PLA_TXFIFO_CTRL */
26562306a36Sopenharmony_ci#define TXFIFO_THR_NORMAL	0x00400008
26662306a36Sopenharmony_ci#define TXFIFO_THR_NORMAL2	0x01000008
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* PLA_DMY_REG0 */
26962306a36Sopenharmony_ci#define ECM_ALDPS		0x0002
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/* PLA_FMC */
27262306a36Sopenharmony_ci#define FMC_FCR_MCU_EN		0x0001
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/* PLA_EEEP_CR */
27562306a36Sopenharmony_ci#define EEEP_CR_EEEP_TX		0x0002
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/* PLA_WDT6_CTRL */
27862306a36Sopenharmony_ci#define WDT6_SET_MODE		0x0010
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/* PLA_TCR0 */
28162306a36Sopenharmony_ci#define TCR0_TX_EMPTY		0x0800
28262306a36Sopenharmony_ci#define TCR0_AUTO_FIFO		0x0080
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* PLA_TCR1 */
28562306a36Sopenharmony_ci#define VERSION_MASK		0x7cf0
28662306a36Sopenharmony_ci#define IFG_MASK		(BIT(3) | BIT(9) | BIT(8))
28762306a36Sopenharmony_ci#define IFG_144NS		BIT(9)
28862306a36Sopenharmony_ci#define IFG_96NS		(BIT(9) | BIT(8))
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci/* PLA_MTPS */
29162306a36Sopenharmony_ci#define MTPS_JUMBO		(12 * 1024 / 64)
29262306a36Sopenharmony_ci#define MTPS_DEFAULT		(6 * 1024 / 64)
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/* PLA_RSTTALLY */
29562306a36Sopenharmony_ci#define TALLY_RESET		0x0001
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/* PLA_CR */
29862306a36Sopenharmony_ci#define CR_RST			0x10
29962306a36Sopenharmony_ci#define CR_RE			0x08
30062306a36Sopenharmony_ci#define CR_TE			0x04
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/* PLA_CRWECR */
30362306a36Sopenharmony_ci#define CRWECR_NORAML		0x00
30462306a36Sopenharmony_ci#define CRWECR_CONFIG		0xc0
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/* PLA_OOB_CTRL */
30762306a36Sopenharmony_ci#define NOW_IS_OOB		0x80
30862306a36Sopenharmony_ci#define TXFIFO_EMPTY		0x20
30962306a36Sopenharmony_ci#define RXFIFO_EMPTY		0x10
31062306a36Sopenharmony_ci#define LINK_LIST_READY		0x02
31162306a36Sopenharmony_ci#define DIS_MCU_CLROOB		0x01
31262306a36Sopenharmony_ci#define FIFO_EMPTY		(TXFIFO_EMPTY | RXFIFO_EMPTY)
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/* PLA_MISC_1 */
31562306a36Sopenharmony_ci#define RXDY_GATED_EN		0x0008
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/* PLA_SFF_STS_7 */
31862306a36Sopenharmony_ci#define RE_INIT_LL		0x8000
31962306a36Sopenharmony_ci#define MCU_BORW_EN		0x4000
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/* PLA_CPCR */
32262306a36Sopenharmony_ci#define FLOW_CTRL_EN		BIT(0)
32362306a36Sopenharmony_ci#define CPCR_RX_VLAN		0x0040
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/* PLA_CFG_WOL */
32662306a36Sopenharmony_ci#define MAGIC_EN		0x0001
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/* PLA_TEREDO_CFG */
32962306a36Sopenharmony_ci#define TEREDO_SEL		0x8000
33062306a36Sopenharmony_ci#define TEREDO_WAKE_MASK	0x7f00
33162306a36Sopenharmony_ci#define TEREDO_RS_EVENT_MASK	0x00fe
33262306a36Sopenharmony_ci#define OOB_TEREDO_EN		0x0001
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/* PLA_BDC_CR */
33562306a36Sopenharmony_ci#define ALDPS_PROXY_MODE	0x0001
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/* PLA_EFUSE_CMD */
33862306a36Sopenharmony_ci#define EFUSE_READ_CMD		BIT(15)
33962306a36Sopenharmony_ci#define EFUSE_DATA_BIT16	BIT(7)
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/* PLA_CONFIG34 */
34262306a36Sopenharmony_ci#define LINK_ON_WAKE_EN		0x0010
34362306a36Sopenharmony_ci#define LINK_OFF_WAKE_EN	0x0008
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/* PLA_CONFIG6 */
34662306a36Sopenharmony_ci#define LANWAKE_CLR_EN		BIT(0)
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/* PLA_USB_CFG */
34962306a36Sopenharmony_ci#define EN_XG_LIP		BIT(1)
35062306a36Sopenharmony_ci#define EN_G_LIP		BIT(2)
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/* PLA_CONFIG5 */
35362306a36Sopenharmony_ci#define BWF_EN			0x0040
35462306a36Sopenharmony_ci#define MWF_EN			0x0020
35562306a36Sopenharmony_ci#define UWF_EN			0x0010
35662306a36Sopenharmony_ci#define LAN_WAKE_EN		0x0002
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/* PLA_LED_FEATURE */
35962306a36Sopenharmony_ci#define LED_MODE_MASK		0x0700
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci/* PLA_PHY_PWR */
36262306a36Sopenharmony_ci#define TX_10M_IDLE_EN		0x0080
36362306a36Sopenharmony_ci#define PFM_PWM_SWITCH		0x0040
36462306a36Sopenharmony_ci#define TEST_IO_OFF		BIT(4)
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/* PLA_MAC_PWR_CTRL */
36762306a36Sopenharmony_ci#define D3_CLK_GATED_EN		0x00004000
36862306a36Sopenharmony_ci#define MCU_CLK_RATIO		0x07010f07
36962306a36Sopenharmony_ci#define MCU_CLK_RATIO_MASK	0x0f0f0f0f
37062306a36Sopenharmony_ci#define ALDPS_SPDWN_RATIO	0x0f87
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/* PLA_MAC_PWR_CTRL2 */
37362306a36Sopenharmony_ci#define EEE_SPDWN_RATIO		0x8007
37462306a36Sopenharmony_ci#define MAC_CLK_SPDWN_EN	BIT(15)
37562306a36Sopenharmony_ci#define EEE_SPDWN_RATIO_MASK	0xff
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/* PLA_MAC_PWR_CTRL3 */
37862306a36Sopenharmony_ci#define PLA_MCU_SPDWN_EN	BIT(14)
37962306a36Sopenharmony_ci#define PKT_AVAIL_SPDWN_EN	0x0100
38062306a36Sopenharmony_ci#define SUSPEND_SPDWN_EN	0x0004
38162306a36Sopenharmony_ci#define U1U2_SPDWN_EN		0x0002
38262306a36Sopenharmony_ci#define L1_SPDWN_EN		0x0001
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/* PLA_MAC_PWR_CTRL4 */
38562306a36Sopenharmony_ci#define PWRSAVE_SPDWN_EN	0x1000
38662306a36Sopenharmony_ci#define RXDV_SPDWN_EN		0x0800
38762306a36Sopenharmony_ci#define TX10MIDLE_EN		0x0100
38862306a36Sopenharmony_ci#define IDLE_SPDWN_EN		BIT(6)
38962306a36Sopenharmony_ci#define TP100_SPDWN_EN		0x0020
39062306a36Sopenharmony_ci#define TP500_SPDWN_EN		0x0010
39162306a36Sopenharmony_ci#define TP1000_SPDWN_EN		0x0008
39262306a36Sopenharmony_ci#define EEE_SPDWN_EN		0x0001
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci/* PLA_GPHY_INTR_IMR */
39562306a36Sopenharmony_ci#define GPHY_STS_MSK		0x0001
39662306a36Sopenharmony_ci#define SPEED_DOWN_MSK		0x0002
39762306a36Sopenharmony_ci#define SPDWN_RXDV_MSK		0x0004
39862306a36Sopenharmony_ci#define SPDWN_LINKCHG_MSK	0x0008
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/* PLA_PHYAR */
40162306a36Sopenharmony_ci#define PHYAR_FLAG		0x80000000
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/* PLA_EEE_CR */
40462306a36Sopenharmony_ci#define EEE_RX_EN		0x0001
40562306a36Sopenharmony_ci#define EEE_TX_EN		0x0002
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci/* PLA_BOOT_CTRL */
40862306a36Sopenharmony_ci#define AUTOLOAD_DONE		0x0002
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/* PLA_LWAKE_CTRL_REG */
41162306a36Sopenharmony_ci#define LANWAKE_PIN		BIT(7)
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/* PLA_SUSPEND_FLAG */
41462306a36Sopenharmony_ci#define LINK_CHG_EVENT		BIT(0)
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/* PLA_INDICATE_FALG */
41762306a36Sopenharmony_ci#define UPCOMING_RUNTIME_D3	BIT(0)
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/* PLA_MACDBG_PRE and PLA_MACDBG_POST */
42062306a36Sopenharmony_ci#define DEBUG_OE		BIT(0)
42162306a36Sopenharmony_ci#define DEBUG_LTSSM		0x0082
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/* PLA_EXTRA_STATUS */
42462306a36Sopenharmony_ci#define CUR_LINK_OK		BIT(15)
42562306a36Sopenharmony_ci#define U3P3_CHECK_EN		BIT(7)	/* RTL_VER_05 only */
42662306a36Sopenharmony_ci#define LINK_CHANGE_FLAG	BIT(8)
42762306a36Sopenharmony_ci#define POLL_LINK_CHG		BIT(0)
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/* PLA_GPHY_CTRL */
43062306a36Sopenharmony_ci#define GPHY_FLASH		BIT(1)
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/* PLA_POL_GPIO_CTRL */
43362306a36Sopenharmony_ci#define DACK_DET_EN		BIT(15)
43462306a36Sopenharmony_ci#define POL_GPHY_PATCH		BIT(4)
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/* USB_USB2PHY */
43762306a36Sopenharmony_ci#define USB2PHY_SUSPEND		0x0001
43862306a36Sopenharmony_ci#define USB2PHY_L1		0x0002
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci/* USB_SSPHYLINK1 */
44162306a36Sopenharmony_ci#define DELAY_PHY_PWR_CHG	BIT(1)
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/* USB_SSPHYLINK2 */
44462306a36Sopenharmony_ci#define pwd_dn_scale_mask	0x3ffe
44562306a36Sopenharmony_ci#define pwd_dn_scale(x)		((x) << 1)
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/* USB_CSR_DUMMY1 */
44862306a36Sopenharmony_ci#define DYNAMIC_BURST		0x0001
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci/* USB_CSR_DUMMY2 */
45162306a36Sopenharmony_ci#define EP4_FULL_FC		0x0001
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci/* USB_DEV_STAT */
45462306a36Sopenharmony_ci#define STAT_SPEED_MASK		0x0006
45562306a36Sopenharmony_ci#define STAT_SPEED_HIGH		0x0000
45662306a36Sopenharmony_ci#define STAT_SPEED_FULL		0x0002
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/* USB_FW_FIX_EN0 */
45962306a36Sopenharmony_ci#define FW_FIX_SUSPEND		BIT(14)
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci/* USB_FW_FIX_EN1 */
46262306a36Sopenharmony_ci#define FW_IP_RESET_EN		BIT(9)
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci/* USB_LPM_CONFIG */
46562306a36Sopenharmony_ci#define LPM_U1U2_EN		BIT(0)
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/* USB_TX_AGG */
46862306a36Sopenharmony_ci#define TX_AGG_MAX_THRESHOLD	0x03
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/* USB_RX_BUF_TH */
47162306a36Sopenharmony_ci#define RX_THR_SUPPER		0x0c350180
47262306a36Sopenharmony_ci#define RX_THR_HIGH		0x7a120180
47362306a36Sopenharmony_ci#define RX_THR_SLOW		0xffff0180
47462306a36Sopenharmony_ci#define RX_THR_B		0x00010001
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/* USB_TX_DMA */
47762306a36Sopenharmony_ci#define TEST_MODE_DISABLE	0x00000001
47862306a36Sopenharmony_ci#define TX_SIZE_ADJUST1		0x00000100
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/* USB_BMU_RESET */
48162306a36Sopenharmony_ci#define BMU_RESET_EP_IN		0x01
48262306a36Sopenharmony_ci#define BMU_RESET_EP_OUT	0x02
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/* USB_BMU_CONFIG */
48562306a36Sopenharmony_ci#define ACT_ODMA		BIT(1)
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/* USB_UPT_RXDMA_OWN */
48862306a36Sopenharmony_ci#define OWN_UPDATE		BIT(0)
48962306a36Sopenharmony_ci#define OWN_CLEAR		BIT(1)
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/* USB_FW_TASK */
49262306a36Sopenharmony_ci#define FC_PATCH_TASK		BIT(1)
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/* USB_RX_AGGR_NUM */
49562306a36Sopenharmony_ci#define RX_AGGR_NUM_MASK	0x1ff
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/* USB_UPS_CTRL */
49862306a36Sopenharmony_ci#define POWER_CUT		0x0100
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/* USB_PM_CTRL_STATUS */
50162306a36Sopenharmony_ci#define RESUME_INDICATE		0x0001
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/* USB_ECM_OPTION */
50462306a36Sopenharmony_ci#define BYPASS_MAC_RESET	BIT(5)
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/* USB_CSTMR */
50762306a36Sopenharmony_ci#define FORCE_SUPER		BIT(0)
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/* USB_MISC_2 */
51062306a36Sopenharmony_ci#define UPS_FORCE_PWR_DOWN	BIT(0)
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci/* USB_ECM_OP */
51362306a36Sopenharmony_ci#define	EN_ALL_SPEED		BIT(0)
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/* USB_GPHY_CTRL */
51662306a36Sopenharmony_ci#define GPHY_PATCH_DONE		BIT(2)
51762306a36Sopenharmony_ci#define BYPASS_FLASH		BIT(5)
51862306a36Sopenharmony_ci#define BACKUP_RESTRORE		BIT(6)
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/* USB_SPEED_OPTION */
52162306a36Sopenharmony_ci#define RG_PWRDN_EN		BIT(8)
52262306a36Sopenharmony_ci#define ALL_SPEED_OFF		BIT(9)
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/* USB_FW_CTRL */
52562306a36Sopenharmony_ci#define FLOW_CTRL_PATCH_OPT	BIT(1)
52662306a36Sopenharmony_ci#define AUTO_SPEEDUP		BIT(3)
52762306a36Sopenharmony_ci#define FLOW_CTRL_PATCH_2	BIT(8)
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/* USB_FC_TIMER */
53062306a36Sopenharmony_ci#define CTRL_TIMER_EN		BIT(15)
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci/* USB_USB_CTRL */
53362306a36Sopenharmony_ci#define CDC_ECM_EN		BIT(3)
53462306a36Sopenharmony_ci#define RX_AGG_DISABLE		0x0010
53562306a36Sopenharmony_ci#define RX_ZERO_EN		0x0080
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/* USB_U2P3_CTRL */
53862306a36Sopenharmony_ci#define U2P3_ENABLE		0x0001
53962306a36Sopenharmony_ci#define RX_DETECT8		BIT(3)
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/* USB_POWER_CUT */
54262306a36Sopenharmony_ci#define PWR_EN			0x0001
54362306a36Sopenharmony_ci#define PHASE2_EN		0x0008
54462306a36Sopenharmony_ci#define UPS_EN			BIT(4)
54562306a36Sopenharmony_ci#define USP_PREWAKE		BIT(5)
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/* USB_MISC_0 */
54862306a36Sopenharmony_ci#define PCUT_STATUS		0x0001
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci/* USB_RX_EARLY_TIMEOUT */
55162306a36Sopenharmony_ci#define COALESCE_SUPER		 85000U
55262306a36Sopenharmony_ci#define COALESCE_HIGH		250000U
55362306a36Sopenharmony_ci#define COALESCE_SLOW		524280U
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci/* USB_WDT1_CTRL */
55662306a36Sopenharmony_ci#define WTD1_EN			BIT(0)
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/* USB_WDT11_CTRL */
55962306a36Sopenharmony_ci#define TIMER11_EN		0x0001
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/* USB_LPM_CTRL */
56262306a36Sopenharmony_ci/* bit 4 ~ 5: fifo empty boundary */
56362306a36Sopenharmony_ci#define FIFO_EMPTY_1FB		0x30	/* 0x1fb * 64 = 32448 bytes */
56462306a36Sopenharmony_ci/* bit 2 ~ 3: LMP timer */
56562306a36Sopenharmony_ci#define LPM_TIMER_MASK		0x0c
56662306a36Sopenharmony_ci#define LPM_TIMER_500MS		0x04	/* 500 ms */
56762306a36Sopenharmony_ci#define LPM_TIMER_500US		0x0c	/* 500 us */
56862306a36Sopenharmony_ci#define ROK_EXIT_LPM		0x02
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/* USB_AFE_CTRL2 */
57162306a36Sopenharmony_ci#define SEN_VAL_MASK		0xf800
57262306a36Sopenharmony_ci#define SEN_VAL_NORMAL		0xa000
57362306a36Sopenharmony_ci#define SEL_RXIDLE		0x0100
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/* USB_UPHY_XTAL */
57662306a36Sopenharmony_ci#define OOBS_POLLING		BIT(8)
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci/* USB_UPS_CFG */
57962306a36Sopenharmony_ci#define SAW_CNT_1MS_MASK	0x0fff
58062306a36Sopenharmony_ci#define MID_REVERSE		BIT(5)	/* RTL8156A */
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci/* USB_UPS_FLAGS */
58362306a36Sopenharmony_ci#define UPS_FLAGS_R_TUNE		BIT(0)
58462306a36Sopenharmony_ci#define UPS_FLAGS_EN_10M_CKDIV		BIT(1)
58562306a36Sopenharmony_ci#define UPS_FLAGS_250M_CKDIV		BIT(2)
58662306a36Sopenharmony_ci#define UPS_FLAGS_EN_ALDPS		BIT(3)
58762306a36Sopenharmony_ci#define UPS_FLAGS_CTAP_SHORT_DIS	BIT(4)
58862306a36Sopenharmony_ci#define UPS_FLAGS_SPEED_MASK		(0xf << 16)
58962306a36Sopenharmony_ci#define ups_flags_speed(x)		((x) << 16)
59062306a36Sopenharmony_ci#define UPS_FLAGS_EN_EEE		BIT(20)
59162306a36Sopenharmony_ci#define UPS_FLAGS_EN_500M_EEE		BIT(21)
59262306a36Sopenharmony_ci#define UPS_FLAGS_EN_EEE_CKDIV		BIT(22)
59362306a36Sopenharmony_ci#define UPS_FLAGS_EEE_PLLOFF_100	BIT(23)
59462306a36Sopenharmony_ci#define UPS_FLAGS_EEE_PLLOFF_GIGA	BIT(24)
59562306a36Sopenharmony_ci#define UPS_FLAGS_EEE_CMOD_LV_EN	BIT(25)
59662306a36Sopenharmony_ci#define UPS_FLAGS_EN_GREEN		BIT(26)
59762306a36Sopenharmony_ci#define UPS_FLAGS_EN_FLOW_CTR		BIT(27)
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cienum spd_duplex {
60062306a36Sopenharmony_ci	NWAY_10M_HALF,
60162306a36Sopenharmony_ci	NWAY_10M_FULL,
60262306a36Sopenharmony_ci	NWAY_100M_HALF,
60362306a36Sopenharmony_ci	NWAY_100M_FULL,
60462306a36Sopenharmony_ci	NWAY_1000M_FULL,
60562306a36Sopenharmony_ci	FORCE_10M_HALF,
60662306a36Sopenharmony_ci	FORCE_10M_FULL,
60762306a36Sopenharmony_ci	FORCE_100M_HALF,
60862306a36Sopenharmony_ci	FORCE_100M_FULL,
60962306a36Sopenharmony_ci	FORCE_1000M_FULL,
61062306a36Sopenharmony_ci	NWAY_2500M_FULL,
61162306a36Sopenharmony_ci};
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci/* OCP_ALDPS_CONFIG */
61462306a36Sopenharmony_ci#define ENPWRSAVE		0x8000
61562306a36Sopenharmony_ci#define ENPDNPS			0x0200
61662306a36Sopenharmony_ci#define LINKENA			0x0100
61762306a36Sopenharmony_ci#define DIS_SDSAVE		0x0010
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/* OCP_PHY_STATUS */
62062306a36Sopenharmony_ci#define PHY_STAT_MASK		0x0007
62162306a36Sopenharmony_ci#define PHY_STAT_EXT_INIT	2
62262306a36Sopenharmony_ci#define PHY_STAT_LAN_ON		3
62362306a36Sopenharmony_ci#define PHY_STAT_PWRDN		5
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/* OCP_INTR_EN */
62662306a36Sopenharmony_ci#define INTR_SPEED_FORCE	BIT(3)
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/* OCP_NCTL_CFG */
62962306a36Sopenharmony_ci#define PGA_RETURN_EN		BIT(1)
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/* OCP_POWER_CFG */
63262306a36Sopenharmony_ci#define EEE_CLKDIV_EN		0x8000
63362306a36Sopenharmony_ci#define EN_ALDPS		0x0004
63462306a36Sopenharmony_ci#define EN_10M_PLLOFF		0x0001
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/* OCP_EEE_CONFIG1 */
63762306a36Sopenharmony_ci#define RG_TXLPI_MSK_HFDUP	0x8000
63862306a36Sopenharmony_ci#define RG_MATCLR_EN		0x4000
63962306a36Sopenharmony_ci#define EEE_10_CAP		0x2000
64062306a36Sopenharmony_ci#define EEE_NWAY_EN		0x1000
64162306a36Sopenharmony_ci#define TX_QUIET_EN		0x0200
64262306a36Sopenharmony_ci#define RX_QUIET_EN		0x0100
64362306a36Sopenharmony_ci#define sd_rise_time_mask	0x0070
64462306a36Sopenharmony_ci#define sd_rise_time(x)		(min(x, 7) << 4)	/* bit 4 ~ 6 */
64562306a36Sopenharmony_ci#define RG_RXLPI_MSK_HFDUP	0x0008
64662306a36Sopenharmony_ci#define SDFALLTIME		0x0007	/* bit 0 ~ 2 */
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci/* OCP_EEE_CONFIG2 */
64962306a36Sopenharmony_ci#define RG_LPIHYS_NUM		0x7000	/* bit 12 ~ 15 */
65062306a36Sopenharmony_ci#define RG_DACQUIET_EN		0x0400
65162306a36Sopenharmony_ci#define RG_LDVQUIET_EN		0x0200
65262306a36Sopenharmony_ci#define RG_CKRSEL		0x0020
65362306a36Sopenharmony_ci#define RG_EEEPRG_EN		0x0010
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci/* OCP_EEE_CONFIG3 */
65662306a36Sopenharmony_ci#define fast_snr_mask		0xff80
65762306a36Sopenharmony_ci#define fast_snr(x)		(min(x, 0x1ff) << 7)	/* bit 7 ~ 15 */
65862306a36Sopenharmony_ci#define RG_LFS_SEL		0x0060	/* bit 6 ~ 5 */
65962306a36Sopenharmony_ci#define MSK_PH			0x0006	/* bit 0 ~ 3 */
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci/* OCP_EEE_AR */
66262306a36Sopenharmony_ci/* bit[15:14] function */
66362306a36Sopenharmony_ci#define FUN_ADDR		0x0000
66462306a36Sopenharmony_ci#define FUN_DATA		0x4000
66562306a36Sopenharmony_ci/* bit[4:0] device addr */
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci/* OCP_EEE_CFG */
66862306a36Sopenharmony_ci#define CTAP_SHORT_EN		0x0040
66962306a36Sopenharmony_ci#define EEE10_EN		0x0010
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci/* OCP_DOWN_SPEED */
67262306a36Sopenharmony_ci#define EN_EEE_CMODE		BIT(14)
67362306a36Sopenharmony_ci#define EN_EEE_1000		BIT(13)
67462306a36Sopenharmony_ci#define EN_EEE_100		BIT(12)
67562306a36Sopenharmony_ci#define EN_10M_CLKDIV		BIT(11)
67662306a36Sopenharmony_ci#define EN_10M_BGOFF		0x0080
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/* OCP_10GBT_CTRL */
67962306a36Sopenharmony_ci#define RTL_ADV2_5G_F_R		BIT(5)	/* Advertise 2.5GBASE-T fast-retrain */
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci/* OCP_PHY_STATE */
68262306a36Sopenharmony_ci#define TXDIS_STATE		0x01
68362306a36Sopenharmony_ci#define ABD_STATE		0x02
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci/* OCP_PHY_PATCH_STAT */
68662306a36Sopenharmony_ci#define PATCH_READY		BIT(6)
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci/* OCP_PHY_PATCH_CMD */
68962306a36Sopenharmony_ci#define PATCH_REQUEST		BIT(4)
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci/* OCP_PHY_LOCK */
69262306a36Sopenharmony_ci#define PATCH_LOCK		BIT(0)
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci/* OCP_ADC_CFG */
69562306a36Sopenharmony_ci#define CKADSEL_L		0x0100
69662306a36Sopenharmony_ci#define ADC_EN			0x0080
69762306a36Sopenharmony_ci#define EN_EMI_L		0x0040
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci/* OCP_SYSCLK_CFG */
70062306a36Sopenharmony_ci#define sysclk_div_expo(x)	(min(x, 5) << 8)
70162306a36Sopenharmony_ci#define clk_div_expo(x)		(min(x, 5) << 4)
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/* SRAM_GREEN_CFG */
70462306a36Sopenharmony_ci#define GREEN_ETH_EN		BIT(15)
70562306a36Sopenharmony_ci#define R_TUNE_EN		BIT(11)
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci/* SRAM_LPF_CFG */
70862306a36Sopenharmony_ci#define LPF_AUTO_TUNE		0x8000
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci/* SRAM_10M_AMP1 */
71162306a36Sopenharmony_ci#define GDAC_IB_UPALL		0x0008
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci/* SRAM_10M_AMP2 */
71462306a36Sopenharmony_ci#define AMP_DN			0x0200
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci/* SRAM_IMPEDANCE */
71762306a36Sopenharmony_ci#define RX_DRIVING_MASK		0x6000
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/* SRAM_PHY_LOCK */
72062306a36Sopenharmony_ci#define PHY_PATCH_LOCK		0x0001
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci/* MAC PASSTHRU */
72362306a36Sopenharmony_ci#define AD_MASK			0xfee0
72462306a36Sopenharmony_ci#define BND_MASK		0x0004
72562306a36Sopenharmony_ci#define BD_MASK			0x0001
72662306a36Sopenharmony_ci#define EFUSE			0xcfdb
72762306a36Sopenharmony_ci#define PASS_THRU_MASK		0x1
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci#define BP4_SUPER_ONLY		0x1578	/* RTL_VER_04 only */
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cienum rtl_register_content {
73262306a36Sopenharmony_ci	_2500bps	= BIT(10),
73362306a36Sopenharmony_ci	_1250bps	= BIT(9),
73462306a36Sopenharmony_ci	_500bps		= BIT(8),
73562306a36Sopenharmony_ci	_tx_flow	= BIT(6),
73662306a36Sopenharmony_ci	_rx_flow	= BIT(5),
73762306a36Sopenharmony_ci	_1000bps	= 0x10,
73862306a36Sopenharmony_ci	_100bps		= 0x08,
73962306a36Sopenharmony_ci	_10bps		= 0x04,
74062306a36Sopenharmony_ci	LINK_STATUS	= 0x02,
74162306a36Sopenharmony_ci	FULL_DUP	= 0x01,
74262306a36Sopenharmony_ci};
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci#define is_speed_2500(_speed)	(((_speed) & (_2500bps | LINK_STATUS)) == (_2500bps | LINK_STATUS))
74562306a36Sopenharmony_ci#define is_flow_control(_speed)	(((_speed) & (_tx_flow | _rx_flow)) == (_tx_flow | _rx_flow))
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci#define RTL8152_MAX_TX		4
74862306a36Sopenharmony_ci#define RTL8152_MAX_RX		10
74962306a36Sopenharmony_ci#define INTBUFSIZE		2
75062306a36Sopenharmony_ci#define TX_ALIGN		4
75162306a36Sopenharmony_ci#define RX_ALIGN		8
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci#define RTL8152_RX_MAX_PENDING	4096
75462306a36Sopenharmony_ci#define RTL8152_RXFG_HEADSZ	256
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci#define INTR_LINK		0x0004
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci#define RTL8152_RMS		(VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
75962306a36Sopenharmony_ci#define RTL8153_RMS		RTL8153_MAX_PACKET
76062306a36Sopenharmony_ci#define RTL8152_TX_TIMEOUT	(5 * HZ)
76162306a36Sopenharmony_ci#define mtu_to_size(m)		((m) + VLAN_ETH_HLEN + ETH_FCS_LEN)
76262306a36Sopenharmony_ci#define size_to_mtu(s)		((s) - VLAN_ETH_HLEN - ETH_FCS_LEN)
76362306a36Sopenharmony_ci#define rx_reserved_size(x)	(mtu_to_size(x) + sizeof(struct rx_desc) + RX_ALIGN)
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci/* rtl8152 flags */
76662306a36Sopenharmony_cienum rtl8152_flags {
76762306a36Sopenharmony_ci	RTL8152_INACCESSIBLE = 0,
76862306a36Sopenharmony_ci	RTL8152_SET_RX_MODE,
76962306a36Sopenharmony_ci	WORK_ENABLE,
77062306a36Sopenharmony_ci	RTL8152_LINK_CHG,
77162306a36Sopenharmony_ci	SELECTIVE_SUSPEND,
77262306a36Sopenharmony_ci	PHY_RESET,
77362306a36Sopenharmony_ci	SCHEDULE_TASKLET,
77462306a36Sopenharmony_ci	GREEN_ETHERNET,
77562306a36Sopenharmony_ci	RX_EPROTO,
77662306a36Sopenharmony_ci	IN_PRE_RESET,
77762306a36Sopenharmony_ci	PROBED_WITH_NO_ERRORS,
77862306a36Sopenharmony_ci	PROBE_SHOULD_RETRY,
77962306a36Sopenharmony_ci};
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci#define DEVICE_ID_LENOVO_USB_C_TRAVEL_HUB		0x721e
78262306a36Sopenharmony_ci#define DEVICE_ID_THINKPAD_ONELINK_PLUS_DOCK		0x3054
78362306a36Sopenharmony_ci#define DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2	0x3082
78462306a36Sopenharmony_ci#define DEVICE_ID_THINKPAD_USB_C_DONGLE			0x720c
78562306a36Sopenharmony_ci#define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2		0xa387
78662306a36Sopenharmony_ci#define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN3		0x3062
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistruct tally_counter {
78962306a36Sopenharmony_ci	__le64	tx_packets;
79062306a36Sopenharmony_ci	__le64	rx_packets;
79162306a36Sopenharmony_ci	__le64	tx_errors;
79262306a36Sopenharmony_ci	__le32	rx_errors;
79362306a36Sopenharmony_ci	__le16	rx_missed;
79462306a36Sopenharmony_ci	__le16	align_errors;
79562306a36Sopenharmony_ci	__le32	tx_one_collision;
79662306a36Sopenharmony_ci	__le32	tx_multi_collision;
79762306a36Sopenharmony_ci	__le64	rx_unicast;
79862306a36Sopenharmony_ci	__le64	rx_broadcast;
79962306a36Sopenharmony_ci	__le32	rx_multicast;
80062306a36Sopenharmony_ci	__le16	tx_aborted;
80162306a36Sopenharmony_ci	__le16	tx_underrun;
80262306a36Sopenharmony_ci};
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistruct rx_desc {
80562306a36Sopenharmony_ci	__le32 opts1;
80662306a36Sopenharmony_ci#define RX_LEN_MASK			0x7fff
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	__le32 opts2;
80962306a36Sopenharmony_ci#define RD_UDP_CS			BIT(23)
81062306a36Sopenharmony_ci#define RD_TCP_CS			BIT(22)
81162306a36Sopenharmony_ci#define RD_IPV6_CS			BIT(20)
81262306a36Sopenharmony_ci#define RD_IPV4_CS			BIT(19)
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	__le32 opts3;
81562306a36Sopenharmony_ci#define IPF				BIT(23) /* IP checksum fail */
81662306a36Sopenharmony_ci#define UDPF				BIT(22) /* UDP checksum fail */
81762306a36Sopenharmony_ci#define TCPF				BIT(21) /* TCP checksum fail */
81862306a36Sopenharmony_ci#define RX_VLAN_TAG			BIT(16)
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	__le32 opts4;
82162306a36Sopenharmony_ci	__le32 opts5;
82262306a36Sopenharmony_ci	__le32 opts6;
82362306a36Sopenharmony_ci};
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistruct tx_desc {
82662306a36Sopenharmony_ci	__le32 opts1;
82762306a36Sopenharmony_ci#define TX_FS			BIT(31) /* First segment of a packet */
82862306a36Sopenharmony_ci#define TX_LS			BIT(30) /* Final segment of a packet */
82962306a36Sopenharmony_ci#define GTSENDV4		BIT(28)
83062306a36Sopenharmony_ci#define GTSENDV6		BIT(27)
83162306a36Sopenharmony_ci#define GTTCPHO_SHIFT		18
83262306a36Sopenharmony_ci#define GTTCPHO_MAX		0x7fU
83362306a36Sopenharmony_ci#define TX_LEN_MAX		0x3ffffU
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	__le32 opts2;
83662306a36Sopenharmony_ci#define UDP_CS			BIT(31) /* Calculate UDP/IP checksum */
83762306a36Sopenharmony_ci#define TCP_CS			BIT(30) /* Calculate TCP/IP checksum */
83862306a36Sopenharmony_ci#define IPV4_CS			BIT(29) /* Calculate IPv4 checksum */
83962306a36Sopenharmony_ci#define IPV6_CS			BIT(28) /* Calculate IPv6 checksum */
84062306a36Sopenharmony_ci#define MSS_SHIFT		17
84162306a36Sopenharmony_ci#define MSS_MAX			0x7ffU
84262306a36Sopenharmony_ci#define TCPHO_SHIFT		17
84362306a36Sopenharmony_ci#define TCPHO_MAX		0x7ffU
84462306a36Sopenharmony_ci#define TX_VLAN_TAG		BIT(16)
84562306a36Sopenharmony_ci};
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistruct r8152;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistruct rx_agg {
85062306a36Sopenharmony_ci	struct list_head list, info_list;
85162306a36Sopenharmony_ci	struct urb *urb;
85262306a36Sopenharmony_ci	struct r8152 *context;
85362306a36Sopenharmony_ci	struct page *page;
85462306a36Sopenharmony_ci	void *buffer;
85562306a36Sopenharmony_ci};
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistruct tx_agg {
85862306a36Sopenharmony_ci	struct list_head list;
85962306a36Sopenharmony_ci	struct urb *urb;
86062306a36Sopenharmony_ci	struct r8152 *context;
86162306a36Sopenharmony_ci	void *buffer;
86262306a36Sopenharmony_ci	void *head;
86362306a36Sopenharmony_ci	u32 skb_num;
86462306a36Sopenharmony_ci	u32 skb_len;
86562306a36Sopenharmony_ci};
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistruct r8152 {
86862306a36Sopenharmony_ci	unsigned long flags;
86962306a36Sopenharmony_ci	struct usb_device *udev;
87062306a36Sopenharmony_ci	struct napi_struct napi;
87162306a36Sopenharmony_ci	struct usb_interface *intf;
87262306a36Sopenharmony_ci	struct net_device *netdev;
87362306a36Sopenharmony_ci	struct urb *intr_urb;
87462306a36Sopenharmony_ci	struct tx_agg tx_info[RTL8152_MAX_TX];
87562306a36Sopenharmony_ci	struct list_head rx_info, rx_used;
87662306a36Sopenharmony_ci	struct list_head rx_done, tx_free;
87762306a36Sopenharmony_ci	struct sk_buff_head tx_queue, rx_queue;
87862306a36Sopenharmony_ci	spinlock_t rx_lock, tx_lock;
87962306a36Sopenharmony_ci	struct delayed_work schedule, hw_phy_work;
88062306a36Sopenharmony_ci	struct mii_if_info mii;
88162306a36Sopenharmony_ci	struct mutex control;	/* use for hw setting */
88262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
88362306a36Sopenharmony_ci	struct notifier_block pm_notifier;
88462306a36Sopenharmony_ci#endif
88562306a36Sopenharmony_ci	struct tasklet_struct tx_tl;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	struct rtl_ops {
88862306a36Sopenharmony_ci		void (*init)(struct r8152 *tp);
88962306a36Sopenharmony_ci		int (*enable)(struct r8152 *tp);
89062306a36Sopenharmony_ci		void (*disable)(struct r8152 *tp);
89162306a36Sopenharmony_ci		void (*up)(struct r8152 *tp);
89262306a36Sopenharmony_ci		void (*down)(struct r8152 *tp);
89362306a36Sopenharmony_ci		void (*unload)(struct r8152 *tp);
89462306a36Sopenharmony_ci		int (*eee_get)(struct r8152 *tp, struct ethtool_eee *eee);
89562306a36Sopenharmony_ci		int (*eee_set)(struct r8152 *tp, struct ethtool_eee *eee);
89662306a36Sopenharmony_ci		bool (*in_nway)(struct r8152 *tp);
89762306a36Sopenharmony_ci		void (*hw_phy_cfg)(struct r8152 *tp);
89862306a36Sopenharmony_ci		void (*autosuspend_en)(struct r8152 *tp, bool enable);
89962306a36Sopenharmony_ci		void (*change_mtu)(struct r8152 *tp);
90062306a36Sopenharmony_ci	} rtl_ops;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	struct ups_info {
90362306a36Sopenharmony_ci		u32 r_tune:1;
90462306a36Sopenharmony_ci		u32 _10m_ckdiv:1;
90562306a36Sopenharmony_ci		u32 _250m_ckdiv:1;
90662306a36Sopenharmony_ci		u32 aldps:1;
90762306a36Sopenharmony_ci		u32 lite_mode:2;
90862306a36Sopenharmony_ci		u32 speed_duplex:4;
90962306a36Sopenharmony_ci		u32 eee:1;
91062306a36Sopenharmony_ci		u32 eee_lite:1;
91162306a36Sopenharmony_ci		u32 eee_ckdiv:1;
91262306a36Sopenharmony_ci		u32 eee_plloff_100:1;
91362306a36Sopenharmony_ci		u32 eee_plloff_giga:1;
91462306a36Sopenharmony_ci		u32 eee_cmod_lv:1;
91562306a36Sopenharmony_ci		u32 green:1;
91662306a36Sopenharmony_ci		u32 flow_control:1;
91762306a36Sopenharmony_ci		u32 ctap_short_off:1;
91862306a36Sopenharmony_ci	} ups_info;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci#define RTL_VER_SIZE		32
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	struct rtl_fw {
92362306a36Sopenharmony_ci		const char *fw_name;
92462306a36Sopenharmony_ci		const struct firmware *fw;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		char version[RTL_VER_SIZE];
92762306a36Sopenharmony_ci		int (*pre_fw)(struct r8152 *tp);
92862306a36Sopenharmony_ci		int (*post_fw)(struct r8152 *tp);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci		bool retry;
93162306a36Sopenharmony_ci	} rtl_fw;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	atomic_t rx_count;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	bool eee_en;
93662306a36Sopenharmony_ci	int intr_interval;
93762306a36Sopenharmony_ci	u32 saved_wolopts;
93862306a36Sopenharmony_ci	u32 msg_enable;
93962306a36Sopenharmony_ci	u32 tx_qlen;
94062306a36Sopenharmony_ci	u32 coalesce;
94162306a36Sopenharmony_ci	u32 advertising;
94262306a36Sopenharmony_ci	u32 rx_buf_sz;
94362306a36Sopenharmony_ci	u32 rx_copybreak;
94462306a36Sopenharmony_ci	u32 rx_pending;
94562306a36Sopenharmony_ci	u32 fc_pause_on, fc_pause_off;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	unsigned int pipe_in, pipe_out, pipe_intr, pipe_ctrl_in, pipe_ctrl_out;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	u32 support_2500full:1;
95062306a36Sopenharmony_ci	u32 lenovo_macpassthru:1;
95162306a36Sopenharmony_ci	u32 dell_tb_rx_agg_bug:1;
95262306a36Sopenharmony_ci	u16 ocp_base;
95362306a36Sopenharmony_ci	u16 speed;
95462306a36Sopenharmony_ci	u16 eee_adv;
95562306a36Sopenharmony_ci	u8 *intr_buff;
95662306a36Sopenharmony_ci	u8 version;
95762306a36Sopenharmony_ci	u8 duplex;
95862306a36Sopenharmony_ci	u8 autoneg;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	unsigned int reg_access_reset_count;
96162306a36Sopenharmony_ci};
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci/**
96462306a36Sopenharmony_ci * struct fw_block - block type and total length
96562306a36Sopenharmony_ci * @type: type of the current block, such as RTL_FW_END, RTL_FW_PLA,
96662306a36Sopenharmony_ci *	RTL_FW_USB and so on.
96762306a36Sopenharmony_ci * @length: total length of the current block.
96862306a36Sopenharmony_ci */
96962306a36Sopenharmony_cistruct fw_block {
97062306a36Sopenharmony_ci	__le32 type;
97162306a36Sopenharmony_ci	__le32 length;
97262306a36Sopenharmony_ci} __packed;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/**
97562306a36Sopenharmony_ci * struct fw_header - header of the firmware file
97662306a36Sopenharmony_ci * @checksum: checksum of sha256 which is calculated from the whole file
97762306a36Sopenharmony_ci *	except the checksum field of the file. That is, calculate sha256
97862306a36Sopenharmony_ci *	from the version field to the end of the file.
97962306a36Sopenharmony_ci * @version: version of this firmware.
98062306a36Sopenharmony_ci * @blocks: the first firmware block of the file
98162306a36Sopenharmony_ci */
98262306a36Sopenharmony_cistruct fw_header {
98362306a36Sopenharmony_ci	u8 checksum[32];
98462306a36Sopenharmony_ci	char version[RTL_VER_SIZE];
98562306a36Sopenharmony_ci	struct fw_block blocks[];
98662306a36Sopenharmony_ci} __packed;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cienum rtl8152_fw_flags {
98962306a36Sopenharmony_ci	FW_FLAGS_USB = 0,
99062306a36Sopenharmony_ci	FW_FLAGS_PLA,
99162306a36Sopenharmony_ci	FW_FLAGS_START,
99262306a36Sopenharmony_ci	FW_FLAGS_STOP,
99362306a36Sopenharmony_ci	FW_FLAGS_NC,
99462306a36Sopenharmony_ci	FW_FLAGS_NC1,
99562306a36Sopenharmony_ci	FW_FLAGS_NC2,
99662306a36Sopenharmony_ci	FW_FLAGS_UC2,
99762306a36Sopenharmony_ci	FW_FLAGS_UC,
99862306a36Sopenharmony_ci	FW_FLAGS_SPEED_UP,
99962306a36Sopenharmony_ci	FW_FLAGS_VER,
100062306a36Sopenharmony_ci};
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cienum rtl8152_fw_fixup_cmd {
100362306a36Sopenharmony_ci	FW_FIXUP_AND = 0,
100462306a36Sopenharmony_ci	FW_FIXUP_OR,
100562306a36Sopenharmony_ci	FW_FIXUP_NOT,
100662306a36Sopenharmony_ci	FW_FIXUP_XOR,
100762306a36Sopenharmony_ci};
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistruct fw_phy_set {
101062306a36Sopenharmony_ci	__le16 addr;
101162306a36Sopenharmony_ci	__le16 data;
101262306a36Sopenharmony_ci} __packed;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_cistruct fw_phy_speed_up {
101562306a36Sopenharmony_ci	struct fw_block blk_hdr;
101662306a36Sopenharmony_ci	__le16 fw_offset;
101762306a36Sopenharmony_ci	__le16 version;
101862306a36Sopenharmony_ci	__le16 fw_reg;
101962306a36Sopenharmony_ci	__le16 reserved;
102062306a36Sopenharmony_ci	char info[];
102162306a36Sopenharmony_ci} __packed;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistruct fw_phy_ver {
102462306a36Sopenharmony_ci	struct fw_block blk_hdr;
102562306a36Sopenharmony_ci	struct fw_phy_set ver;
102662306a36Sopenharmony_ci	__le32 reserved;
102762306a36Sopenharmony_ci} __packed;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistruct fw_phy_fixup {
103062306a36Sopenharmony_ci	struct fw_block blk_hdr;
103162306a36Sopenharmony_ci	struct fw_phy_set setting;
103262306a36Sopenharmony_ci	__le16 bit_cmd;
103362306a36Sopenharmony_ci	__le16 reserved;
103462306a36Sopenharmony_ci} __packed;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistruct fw_phy_union {
103762306a36Sopenharmony_ci	struct fw_block blk_hdr;
103862306a36Sopenharmony_ci	__le16 fw_offset;
103962306a36Sopenharmony_ci	__le16 fw_reg;
104062306a36Sopenharmony_ci	struct fw_phy_set pre_set[2];
104162306a36Sopenharmony_ci	struct fw_phy_set bp[8];
104262306a36Sopenharmony_ci	struct fw_phy_set bp_en;
104362306a36Sopenharmony_ci	u8 pre_num;
104462306a36Sopenharmony_ci	u8 bp_num;
104562306a36Sopenharmony_ci	char info[];
104662306a36Sopenharmony_ci} __packed;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci/**
104962306a36Sopenharmony_ci * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB.
105062306a36Sopenharmony_ci *	The layout of the firmware block is:
105162306a36Sopenharmony_ci *	<struct fw_mac> + <info> + <firmware data>.
105262306a36Sopenharmony_ci * @blk_hdr: firmware descriptor (type, length)
105362306a36Sopenharmony_ci * @fw_offset: offset of the firmware binary data. The start address of
105462306a36Sopenharmony_ci *	the data would be the address of struct fw_mac + @fw_offset.
105562306a36Sopenharmony_ci * @fw_reg: the register to load the firmware. Depends on chip.
105662306a36Sopenharmony_ci * @bp_ba_addr: the register to write break point base address. Depends on
105762306a36Sopenharmony_ci *	chip.
105862306a36Sopenharmony_ci * @bp_ba_value: break point base address. Depends on chip.
105962306a36Sopenharmony_ci * @bp_en_addr: the register to write break point enabled mask. Depends
106062306a36Sopenharmony_ci *	on chip.
106162306a36Sopenharmony_ci * @bp_en_value: break point enabled mask. Depends on the firmware.
106262306a36Sopenharmony_ci * @bp_start: the start register of break points. Depends on chip.
106362306a36Sopenharmony_ci * @bp_num: the break point number which needs to be set for this firmware.
106462306a36Sopenharmony_ci *	Depends on the firmware.
106562306a36Sopenharmony_ci * @bp: break points. Depends on firmware.
106662306a36Sopenharmony_ci * @reserved: reserved space (unused)
106762306a36Sopenharmony_ci * @fw_ver_reg: the register to store the fw version.
106862306a36Sopenharmony_ci * @fw_ver_data: the firmware version of the current type.
106962306a36Sopenharmony_ci * @info: additional information for debugging, and is followed by the
107062306a36Sopenharmony_ci *	binary data of firmware.
107162306a36Sopenharmony_ci */
107262306a36Sopenharmony_cistruct fw_mac {
107362306a36Sopenharmony_ci	struct fw_block blk_hdr;
107462306a36Sopenharmony_ci	__le16 fw_offset;
107562306a36Sopenharmony_ci	__le16 fw_reg;
107662306a36Sopenharmony_ci	__le16 bp_ba_addr;
107762306a36Sopenharmony_ci	__le16 bp_ba_value;
107862306a36Sopenharmony_ci	__le16 bp_en_addr;
107962306a36Sopenharmony_ci	__le16 bp_en_value;
108062306a36Sopenharmony_ci	__le16 bp_start;
108162306a36Sopenharmony_ci	__le16 bp_num;
108262306a36Sopenharmony_ci	__le16 bp[16]; /* any value determined by firmware */
108362306a36Sopenharmony_ci	__le32 reserved;
108462306a36Sopenharmony_ci	__le16 fw_ver_reg;
108562306a36Sopenharmony_ci	u8 fw_ver_data;
108662306a36Sopenharmony_ci	char info[];
108762306a36Sopenharmony_ci} __packed;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci/**
109062306a36Sopenharmony_ci * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START.
109162306a36Sopenharmony_ci *	This is used to set patch key when loading the firmware of PHY.
109262306a36Sopenharmony_ci * @blk_hdr: firmware descriptor (type, length)
109362306a36Sopenharmony_ci * @key_reg: the register to write the patch key.
109462306a36Sopenharmony_ci * @key_data: patch key.
109562306a36Sopenharmony_ci * @reserved: reserved space (unused)
109662306a36Sopenharmony_ci */
109762306a36Sopenharmony_cistruct fw_phy_patch_key {
109862306a36Sopenharmony_ci	struct fw_block blk_hdr;
109962306a36Sopenharmony_ci	__le16 key_reg;
110062306a36Sopenharmony_ci	__le16 key_data;
110162306a36Sopenharmony_ci	__le32 reserved;
110262306a36Sopenharmony_ci} __packed;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci/**
110562306a36Sopenharmony_ci * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC.
110662306a36Sopenharmony_ci *	The layout of the firmware block is:
110762306a36Sopenharmony_ci *	<struct fw_phy_nc> + <info> + <firmware data>.
110862306a36Sopenharmony_ci * @blk_hdr: firmware descriptor (type, length)
110962306a36Sopenharmony_ci * @fw_offset: offset of the firmware binary data. The start address of
111062306a36Sopenharmony_ci *	the data would be the address of struct fw_phy_nc + @fw_offset.
111162306a36Sopenharmony_ci * @fw_reg: the register to load the firmware. Depends on chip.
111262306a36Sopenharmony_ci * @ba_reg: the register to write the base address. Depends on chip.
111362306a36Sopenharmony_ci * @ba_data: base address. Depends on chip.
111462306a36Sopenharmony_ci * @patch_en_addr: the register of enabling patch mode. Depends on chip.
111562306a36Sopenharmony_ci * @patch_en_value: patch mode enabled mask. Depends on the firmware.
111662306a36Sopenharmony_ci * @mode_reg: the regitster of switching the mode.
111762306a36Sopenharmony_ci * @mode_pre: the mode needing to be set before loading the firmware.
111862306a36Sopenharmony_ci * @mode_post: the mode to be set when finishing to load the firmware.
111962306a36Sopenharmony_ci * @reserved: reserved space (unused)
112062306a36Sopenharmony_ci * @bp_start: the start register of break points. Depends on chip.
112162306a36Sopenharmony_ci * @bp_num: the break point number which needs to be set for this firmware.
112262306a36Sopenharmony_ci *	Depends on the firmware.
112362306a36Sopenharmony_ci * @bp: break points. Depends on firmware.
112462306a36Sopenharmony_ci * @info: additional information for debugging, and is followed by the
112562306a36Sopenharmony_ci *	binary data of firmware.
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_cistruct fw_phy_nc {
112862306a36Sopenharmony_ci	struct fw_block blk_hdr;
112962306a36Sopenharmony_ci	__le16 fw_offset;
113062306a36Sopenharmony_ci	__le16 fw_reg;
113162306a36Sopenharmony_ci	__le16 ba_reg;
113262306a36Sopenharmony_ci	__le16 ba_data;
113362306a36Sopenharmony_ci	__le16 patch_en_addr;
113462306a36Sopenharmony_ci	__le16 patch_en_value;
113562306a36Sopenharmony_ci	__le16 mode_reg;
113662306a36Sopenharmony_ci	__le16 mode_pre;
113762306a36Sopenharmony_ci	__le16 mode_post;
113862306a36Sopenharmony_ci	__le16 reserved;
113962306a36Sopenharmony_ci	__le16 bp_start;
114062306a36Sopenharmony_ci	__le16 bp_num;
114162306a36Sopenharmony_ci	__le16 bp[4];
114262306a36Sopenharmony_ci	char info[];
114362306a36Sopenharmony_ci} __packed;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cienum rtl_fw_type {
114662306a36Sopenharmony_ci	RTL_FW_END = 0,
114762306a36Sopenharmony_ci	RTL_FW_PLA,
114862306a36Sopenharmony_ci	RTL_FW_USB,
114962306a36Sopenharmony_ci	RTL_FW_PHY_START,
115062306a36Sopenharmony_ci	RTL_FW_PHY_STOP,
115162306a36Sopenharmony_ci	RTL_FW_PHY_NC,
115262306a36Sopenharmony_ci	RTL_FW_PHY_FIXUP,
115362306a36Sopenharmony_ci	RTL_FW_PHY_UNION_NC,
115462306a36Sopenharmony_ci	RTL_FW_PHY_UNION_NC1,
115562306a36Sopenharmony_ci	RTL_FW_PHY_UNION_NC2,
115662306a36Sopenharmony_ci	RTL_FW_PHY_UNION_UC2,
115762306a36Sopenharmony_ci	RTL_FW_PHY_UNION_UC,
115862306a36Sopenharmony_ci	RTL_FW_PHY_UNION_MISC,
115962306a36Sopenharmony_ci	RTL_FW_PHY_SPEED_UP,
116062306a36Sopenharmony_ci	RTL_FW_PHY_VER,
116162306a36Sopenharmony_ci};
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_cienum rtl_version {
116462306a36Sopenharmony_ci	RTL_VER_UNKNOWN = 0,
116562306a36Sopenharmony_ci	RTL_VER_01,
116662306a36Sopenharmony_ci	RTL_VER_02,
116762306a36Sopenharmony_ci	RTL_VER_03,
116862306a36Sopenharmony_ci	RTL_VER_04,
116962306a36Sopenharmony_ci	RTL_VER_05,
117062306a36Sopenharmony_ci	RTL_VER_06,
117162306a36Sopenharmony_ci	RTL_VER_07,
117262306a36Sopenharmony_ci	RTL_VER_08,
117362306a36Sopenharmony_ci	RTL_VER_09,
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	RTL_TEST_01,
117662306a36Sopenharmony_ci	RTL_VER_10,
117762306a36Sopenharmony_ci	RTL_VER_11,
117862306a36Sopenharmony_ci	RTL_VER_12,
117962306a36Sopenharmony_ci	RTL_VER_13,
118062306a36Sopenharmony_ci	RTL_VER_14,
118162306a36Sopenharmony_ci	RTL_VER_15,
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	RTL_VER_MAX
118462306a36Sopenharmony_ci};
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cienum tx_csum_stat {
118762306a36Sopenharmony_ci	TX_CSUM_SUCCESS = 0,
118862306a36Sopenharmony_ci	TX_CSUM_TSO,
118962306a36Sopenharmony_ci	TX_CSUM_NONE
119062306a36Sopenharmony_ci};
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci#define RTL_ADVERTISED_10_HALF			BIT(0)
119362306a36Sopenharmony_ci#define RTL_ADVERTISED_10_FULL			BIT(1)
119462306a36Sopenharmony_ci#define RTL_ADVERTISED_100_HALF			BIT(2)
119562306a36Sopenharmony_ci#define RTL_ADVERTISED_100_FULL			BIT(3)
119662306a36Sopenharmony_ci#define RTL_ADVERTISED_1000_HALF		BIT(4)
119762306a36Sopenharmony_ci#define RTL_ADVERTISED_1000_FULL		BIT(5)
119862306a36Sopenharmony_ci#define RTL_ADVERTISED_2500_FULL		BIT(6)
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
120162306a36Sopenharmony_ci * The RTL chips use a 64 element hash table based on the Ethernet CRC.
120262306a36Sopenharmony_ci */
120362306a36Sopenharmony_cistatic const int multicast_filter_limit = 32;
120462306a36Sopenharmony_cistatic unsigned int agg_buf_sz = 16384;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci#define RTL_LIMITED_TSO_SIZE	(size_to_mtu(agg_buf_sz) - sizeof(struct tx_desc))
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci/* If register access fails then we block access and issue a reset. If this
120962306a36Sopenharmony_ci * happens too many times in a row without a successful access then we stop
121062306a36Sopenharmony_ci * trying to reset and just leave access blocked.
121162306a36Sopenharmony_ci */
121262306a36Sopenharmony_ci#define REGISTER_ACCESS_MAX_RESETS	3
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic void rtl_set_inaccessible(struct r8152 *tp)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	set_bit(RTL8152_INACCESSIBLE, &tp->flags);
121762306a36Sopenharmony_ci	smp_mb__after_atomic();
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_cistatic void rtl_set_accessible(struct r8152 *tp)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	clear_bit(RTL8152_INACCESSIBLE, &tp->flags);
122362306a36Sopenharmony_ci	smp_mb__after_atomic();
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic
122762306a36Sopenharmony_ciint r8152_control_msg(struct r8152 *tp, unsigned int pipe, __u8 request,
122862306a36Sopenharmony_ci		      __u8 requesttype, __u16 value, __u16 index, void *data,
122962306a36Sopenharmony_ci		      __u16 size, const char *msg_tag)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct usb_device *udev = tp->udev;
123262306a36Sopenharmony_ci	int ret;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
123562306a36Sopenharmony_ci		return -ENODEV;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	ret = usb_control_msg(udev, pipe, request, requesttype,
123862306a36Sopenharmony_ci			      value, index, data, size,
123962306a36Sopenharmony_ci			      USB_CTRL_GET_TIMEOUT);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/* No need to issue a reset to report an error if the USB device got
124262306a36Sopenharmony_ci	 * unplugged; just return immediately.
124362306a36Sopenharmony_ci	 */
124462306a36Sopenharmony_ci	if (ret == -ENODEV)
124562306a36Sopenharmony_ci		return ret;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* If the write was successful then we're done */
124862306a36Sopenharmony_ci	if (ret >= 0) {
124962306a36Sopenharmony_ci		tp->reg_access_reset_count = 0;
125062306a36Sopenharmony_ci		return ret;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	dev_err(&udev->dev,
125462306a36Sopenharmony_ci		"Failed to %s %d bytes at %#06x/%#06x (%d)\n",
125562306a36Sopenharmony_ci		msg_tag, size, value, index, ret);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	/* Block all future register access until we reset. Much of the code
125862306a36Sopenharmony_ci	 * in the driver doesn't check for errors. Notably, many parts of the
125962306a36Sopenharmony_ci	 * driver do a read/modify/write of a register value without
126062306a36Sopenharmony_ci	 * confirming that the read succeeded. Writing back modified garbage
126162306a36Sopenharmony_ci	 * like this can fully wedge the adapter, requiring a power cycle.
126262306a36Sopenharmony_ci	 */
126362306a36Sopenharmony_ci	rtl_set_inaccessible(tp);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/* If probe hasn't yet finished, then we'll request a retry of the
126662306a36Sopenharmony_ci	 * whole probe routine if we get any control transfer errors. We
126762306a36Sopenharmony_ci	 * never have to clear this bit since we free/reallocate the whole "tp"
126862306a36Sopenharmony_ci	 * structure if we retry probe.
126962306a36Sopenharmony_ci	 */
127062306a36Sopenharmony_ci	if (!test_bit(PROBED_WITH_NO_ERRORS, &tp->flags)) {
127162306a36Sopenharmony_ci		set_bit(PROBE_SHOULD_RETRY, &tp->flags);
127262306a36Sopenharmony_ci		return ret;
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* Failing to access registers in pre-reset is not surprising since we
127662306a36Sopenharmony_ci	 * wouldn't be resetting if things were behaving normally. The register
127762306a36Sopenharmony_ci	 * access we do in pre-reset isn't truly mandatory--we're just reusing
127862306a36Sopenharmony_ci	 * the disable() function and trying to be nice by powering the
127962306a36Sopenharmony_ci	 * adapter down before resetting it. Thus, if we're in pre-reset,
128062306a36Sopenharmony_ci	 * we'll return right away and not try to queue up yet another reset.
128162306a36Sopenharmony_ci	 * We know the post-reset is already coming.
128262306a36Sopenharmony_ci	 */
128362306a36Sopenharmony_ci	if (test_bit(IN_PRE_RESET, &tp->flags))
128462306a36Sopenharmony_ci		return ret;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (tp->reg_access_reset_count < REGISTER_ACCESS_MAX_RESETS) {
128762306a36Sopenharmony_ci		usb_queue_reset_device(tp->intf);
128862306a36Sopenharmony_ci		tp->reg_access_reset_count++;
128962306a36Sopenharmony_ci	} else if (tp->reg_access_reset_count == REGISTER_ACCESS_MAX_RESETS) {
129062306a36Sopenharmony_ci		dev_err(&udev->dev,
129162306a36Sopenharmony_ci			"Tried to reset %d times; giving up.\n",
129262306a36Sopenharmony_ci			REGISTER_ACCESS_MAX_RESETS);
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	return ret;
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic
129962306a36Sopenharmony_ciint get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	int ret;
130262306a36Sopenharmony_ci	void *tmp;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	tmp = kmalloc(size, GFP_KERNEL);
130562306a36Sopenharmony_ci	if (!tmp)
130662306a36Sopenharmony_ci		return -ENOMEM;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	ret = r8152_control_msg(tp, tp->pipe_ctrl_in,
130962306a36Sopenharmony_ci				RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
131062306a36Sopenharmony_ci				value, index, tmp, size, "read");
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (ret < 0)
131362306a36Sopenharmony_ci		memset(data, 0xff, size);
131462306a36Sopenharmony_ci	else
131562306a36Sopenharmony_ci		memcpy(data, tmp, size);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	kfree(tmp);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	return ret;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic
132362306a36Sopenharmony_ciint set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	int ret;
132662306a36Sopenharmony_ci	void *tmp;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	tmp = kmemdup(data, size, GFP_KERNEL);
132962306a36Sopenharmony_ci	if (!tmp)
133062306a36Sopenharmony_ci		return -ENOMEM;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	ret = r8152_control_msg(tp, tp->pipe_ctrl_out,
133362306a36Sopenharmony_ci				RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
133462306a36Sopenharmony_ci				value, index, tmp, size, "write");
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	kfree(tmp);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	return ret;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic void rtl_set_unplug(struct r8152 *tp)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	if (tp->udev->state == USB_STATE_NOTATTACHED)
134462306a36Sopenharmony_ci		rtl_set_inaccessible(tp);
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_cistatic int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
134862306a36Sopenharmony_ci			    void *data, u16 type)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	u16 limit = 64;
135162306a36Sopenharmony_ci	int ret = 0;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
135462306a36Sopenharmony_ci		return -ENODEV;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	/* both size and indix must be 4 bytes align */
135762306a36Sopenharmony_ci	if ((size & 3) || !size || (index & 3) || !data)
135862306a36Sopenharmony_ci		return -EPERM;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	if ((u32)index + (u32)size > 0xffff)
136162306a36Sopenharmony_ci		return -EPERM;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	while (size) {
136462306a36Sopenharmony_ci		if (size > limit) {
136562306a36Sopenharmony_ci			ret = get_registers(tp, index, type, limit, data);
136662306a36Sopenharmony_ci			if (ret < 0)
136762306a36Sopenharmony_ci				break;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci			index += limit;
137062306a36Sopenharmony_ci			data += limit;
137162306a36Sopenharmony_ci			size -= limit;
137262306a36Sopenharmony_ci		} else {
137362306a36Sopenharmony_ci			ret = get_registers(tp, index, type, size, data);
137462306a36Sopenharmony_ci			if (ret < 0)
137562306a36Sopenharmony_ci				break;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci			index += size;
137862306a36Sopenharmony_ci			data += size;
137962306a36Sopenharmony_ci			size = 0;
138062306a36Sopenharmony_ci			break;
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	if (ret == -ENODEV)
138562306a36Sopenharmony_ci		rtl_set_unplug(tp);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return ret;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
139162306a36Sopenharmony_ci			     u16 size, void *data, u16 type)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	int ret;
139462306a36Sopenharmony_ci	u16 byteen_start, byteen_end, byen;
139562306a36Sopenharmony_ci	u16 limit = 512;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
139862306a36Sopenharmony_ci		return -ENODEV;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* both size and indix must be 4 bytes align */
140162306a36Sopenharmony_ci	if ((size & 3) || !size || (index & 3) || !data)
140262306a36Sopenharmony_ci		return -EPERM;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	if ((u32)index + (u32)size > 0xffff)
140562306a36Sopenharmony_ci		return -EPERM;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	byteen_start = byteen & BYTE_EN_START_MASK;
140862306a36Sopenharmony_ci	byteen_end = byteen & BYTE_EN_END_MASK;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	byen = byteen_start | (byteen_start << 4);
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/* Split the first DWORD if the byte_en is not 0xff */
141362306a36Sopenharmony_ci	if (byen != BYTE_EN_DWORD) {
141462306a36Sopenharmony_ci		ret = set_registers(tp, index, type | byen, 4, data);
141562306a36Sopenharmony_ci		if (ret < 0)
141662306a36Sopenharmony_ci			goto error1;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci		index += 4;
141962306a36Sopenharmony_ci		data += 4;
142062306a36Sopenharmony_ci		size -= 4;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (size) {
142462306a36Sopenharmony_ci		byen = byteen_end | (byteen_end >> 4);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci		/* Split the last DWORD if the byte_en is not 0xff */
142762306a36Sopenharmony_ci		if (byen != BYTE_EN_DWORD)
142862306a36Sopenharmony_ci			size -= 4;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		while (size) {
143162306a36Sopenharmony_ci			if (size > limit) {
143262306a36Sopenharmony_ci				ret = set_registers(tp, index,
143362306a36Sopenharmony_ci						    type | BYTE_EN_DWORD,
143462306a36Sopenharmony_ci						    limit, data);
143562306a36Sopenharmony_ci				if (ret < 0)
143662306a36Sopenharmony_ci					goto error1;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci				index += limit;
143962306a36Sopenharmony_ci				data += limit;
144062306a36Sopenharmony_ci				size -= limit;
144162306a36Sopenharmony_ci			} else {
144262306a36Sopenharmony_ci				ret = set_registers(tp, index,
144362306a36Sopenharmony_ci						    type | BYTE_EN_DWORD,
144462306a36Sopenharmony_ci						    size, data);
144562306a36Sopenharmony_ci				if (ret < 0)
144662306a36Sopenharmony_ci					goto error1;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci				index += size;
144962306a36Sopenharmony_ci				data += size;
145062306a36Sopenharmony_ci				size = 0;
145162306a36Sopenharmony_ci				break;
145262306a36Sopenharmony_ci			}
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		/* Set the last DWORD */
145662306a36Sopenharmony_ci		if (byen != BYTE_EN_DWORD)
145762306a36Sopenharmony_ci			ret = set_registers(tp, index, type | byen, 4, data);
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cierror1:
146162306a36Sopenharmony_ci	if (ret == -ENODEV)
146262306a36Sopenharmony_ci		rtl_set_unplug(tp);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	return ret;
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_cistatic inline
146862306a36Sopenharmony_ciint pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
147162306a36Sopenharmony_ci}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_cistatic inline
147462306a36Sopenharmony_ciint pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic inline
148062306a36Sopenharmony_ciint usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
148362306a36Sopenharmony_ci}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_cistatic u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	__le32 data;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	generic_ocp_read(tp, index, sizeof(data), &data, type);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	return __le32_to_cpu(data);
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	__le32 tmp = __cpu_to_le32(data);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	u32 data;
150462306a36Sopenharmony_ci	__le32 tmp;
150562306a36Sopenharmony_ci	u16 byen = BYTE_EN_WORD;
150662306a36Sopenharmony_ci	u8 shift = index & 2;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	index &= ~3;
150962306a36Sopenharmony_ci	byen <<= shift;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type | byen);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	data = __le32_to_cpu(tmp);
151462306a36Sopenharmony_ci	data >>= (shift * 8);
151562306a36Sopenharmony_ci	data &= 0xffff;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	return (u16)data;
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cistatic void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	u32 mask = 0xffff;
152362306a36Sopenharmony_ci	__le32 tmp;
152462306a36Sopenharmony_ci	u16 byen = BYTE_EN_WORD;
152562306a36Sopenharmony_ci	u8 shift = index & 2;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	data &= mask;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (index & 2) {
153062306a36Sopenharmony_ci		byen <<= shift;
153162306a36Sopenharmony_ci		mask <<= (shift * 8);
153262306a36Sopenharmony_ci		data <<= (shift * 8);
153362306a36Sopenharmony_ci		index &= ~3;
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	tmp = __cpu_to_le32(data);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci	u32 data;
154462306a36Sopenharmony_ci	__le32 tmp;
154562306a36Sopenharmony_ci	u8 shift = index & 3;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	index &= ~3;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	data = __le32_to_cpu(tmp);
155262306a36Sopenharmony_ci	data >>= (shift * 8);
155362306a36Sopenharmony_ci	data &= 0xff;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	return (u8)data;
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_cistatic void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
155962306a36Sopenharmony_ci{
156062306a36Sopenharmony_ci	u32 mask = 0xff;
156162306a36Sopenharmony_ci	__le32 tmp;
156262306a36Sopenharmony_ci	u16 byen = BYTE_EN_BYTE;
156362306a36Sopenharmony_ci	u8 shift = index & 3;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	data &= mask;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (index & 3) {
156862306a36Sopenharmony_ci		byen <<= shift;
156962306a36Sopenharmony_ci		mask <<= (shift * 8);
157062306a36Sopenharmony_ci		data <<= (shift * 8);
157162306a36Sopenharmony_ci		index &= ~3;
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	tmp = __cpu_to_le32(data);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic u16 ocp_reg_read(struct r8152 *tp, u16 addr)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	u16 ocp_base, ocp_index;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	ocp_base = addr & 0xf000;
158462306a36Sopenharmony_ci	if (ocp_base != tp->ocp_base) {
158562306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
158662306a36Sopenharmony_ci		tp->ocp_base = ocp_base;
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	ocp_index = (addr & 0x0fff) | 0xb000;
159062306a36Sopenharmony_ci	return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	u16 ocp_base, ocp_index;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	ocp_base = addr & 0xf000;
159862306a36Sopenharmony_ci	if (ocp_base != tp->ocp_base) {
159962306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
160062306a36Sopenharmony_ci		tp->ocp_base = ocp_base;
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	ocp_index = (addr & 0x0fff) | 0xb000;
160462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_cistatic void sram_write(struct r8152 *tp, u16 addr, u16 data)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
162062306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_SRAM_DATA, data);
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistatic u16 sram_read(struct r8152 *tp, u16 addr)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
162662306a36Sopenharmony_ci	return ocp_reg_read(tp, OCP_SRAM_DATA);
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic int read_mii_word(struct net_device *netdev, int phy_id, int reg)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
163262306a36Sopenharmony_ci	int ret;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
163562306a36Sopenharmony_ci		return -ENODEV;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	if (phy_id != R8152_PHY_ID)
163862306a36Sopenharmony_ci		return -EINVAL;
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	ret = r8152_mdio_read(tp, reg);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	return ret;
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic
164662306a36Sopenharmony_civoid write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
165162306a36Sopenharmony_ci		return;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	if (phy_id != R8152_PHY_ID)
165462306a36Sopenharmony_ci		return;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	r8152_mdio_write(tp, reg, val);
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cistatic int
166062306a36Sopenharmony_cir8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic int
166362306a36Sopenharmony_cirtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
166462306a36Sopenharmony_ci		  u32 advertising);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cistatic int __rtl8152_set_mac_address(struct net_device *netdev, void *p,
166762306a36Sopenharmony_ci				     bool in_resume)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
167062306a36Sopenharmony_ci	struct sockaddr *addr = p;
167162306a36Sopenharmony_ci	int ret = -EADDRNOTAVAIL;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
167462306a36Sopenharmony_ci		goto out1;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	if (!in_resume) {
167762306a36Sopenharmony_ci		ret = usb_autopm_get_interface(tp->intf);
167862306a36Sopenharmony_ci		if (ret < 0)
167962306a36Sopenharmony_ci			goto out1;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	mutex_lock(&tp->control);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	eth_hw_addr_set(netdev, addr->sa_data);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
168762306a36Sopenharmony_ci	pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data);
168862306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	mutex_unlock(&tp->control);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	if (!in_resume)
169362306a36Sopenharmony_ci		usb_autopm_put_interface(tp->intf);
169462306a36Sopenharmony_ciout1:
169562306a36Sopenharmony_ci	return ret;
169662306a36Sopenharmony_ci}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cistatic int rtl8152_set_mac_address(struct net_device *netdev, void *p)
169962306a36Sopenharmony_ci{
170062306a36Sopenharmony_ci	return __rtl8152_set_mac_address(netdev, p, false);
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci/* Devices containing proper chips can support a persistent
170462306a36Sopenharmony_ci * host system provided MAC address.
170562306a36Sopenharmony_ci * Examples of this are Dell TB15 and Dell WD15 docks
170662306a36Sopenharmony_ci */
170762306a36Sopenharmony_cistatic int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	acpi_status status;
171062306a36Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
171162306a36Sopenharmony_ci	union acpi_object *obj;
171262306a36Sopenharmony_ci	int ret = -EINVAL;
171362306a36Sopenharmony_ci	u32 ocp_data;
171462306a36Sopenharmony_ci	unsigned char buf[6];
171562306a36Sopenharmony_ci	char *mac_obj_name;
171662306a36Sopenharmony_ci	acpi_object_type mac_obj_type;
171762306a36Sopenharmony_ci	int mac_strlen;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	if (tp->lenovo_macpassthru) {
172062306a36Sopenharmony_ci		mac_obj_name = "\\MACA";
172162306a36Sopenharmony_ci		mac_obj_type = ACPI_TYPE_STRING;
172262306a36Sopenharmony_ci		mac_strlen = 0x16;
172362306a36Sopenharmony_ci	} else {
172462306a36Sopenharmony_ci		/* test for -AD variant of RTL8153 */
172562306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
172662306a36Sopenharmony_ci		if ((ocp_data & AD_MASK) == 0x1000) {
172762306a36Sopenharmony_ci			/* test for MAC address pass-through bit */
172862306a36Sopenharmony_ci			ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE);
172962306a36Sopenharmony_ci			if ((ocp_data & PASS_THRU_MASK) != 1) {
173062306a36Sopenharmony_ci				netif_dbg(tp, probe, tp->netdev,
173162306a36Sopenharmony_ci						"No efuse for RTL8153-AD MAC pass through\n");
173262306a36Sopenharmony_ci				return -ENODEV;
173362306a36Sopenharmony_ci			}
173462306a36Sopenharmony_ci		} else {
173562306a36Sopenharmony_ci			/* test for RTL8153-BND and RTL8153-BD */
173662306a36Sopenharmony_ci			ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1);
173762306a36Sopenharmony_ci			if ((ocp_data & BND_MASK) == 0 && (ocp_data & BD_MASK) == 0) {
173862306a36Sopenharmony_ci				netif_dbg(tp, probe, tp->netdev,
173962306a36Sopenharmony_ci						"Invalid variant for MAC pass through\n");
174062306a36Sopenharmony_ci				return -ENODEV;
174162306a36Sopenharmony_ci			}
174262306a36Sopenharmony_ci		}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci		mac_obj_name = "\\_SB.AMAC";
174562306a36Sopenharmony_ci		mac_obj_type = ACPI_TYPE_BUFFER;
174662306a36Sopenharmony_ci		mac_strlen = 0x17;
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	/* returns _AUXMAC_#AABBCCDDEEFF# */
175062306a36Sopenharmony_ci	status = acpi_evaluate_object(NULL, mac_obj_name, NULL, &buffer);
175162306a36Sopenharmony_ci	obj = (union acpi_object *)buffer.pointer;
175262306a36Sopenharmony_ci	if (!ACPI_SUCCESS(status))
175362306a36Sopenharmony_ci		return -ENODEV;
175462306a36Sopenharmony_ci	if (obj->type != mac_obj_type || obj->string.length != mac_strlen) {
175562306a36Sopenharmony_ci		netif_warn(tp, probe, tp->netdev,
175662306a36Sopenharmony_ci			   "Invalid buffer for pass-thru MAC addr: (%d, %d)\n",
175762306a36Sopenharmony_ci			   obj->type, obj->string.length);
175862306a36Sopenharmony_ci		goto amacout;
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) != 0 ||
176262306a36Sopenharmony_ci	    strncmp(obj->string.pointer + 0x15, "#", 1) != 0) {
176362306a36Sopenharmony_ci		netif_warn(tp, probe, tp->netdev,
176462306a36Sopenharmony_ci			   "Invalid header when reading pass-thru MAC addr\n");
176562306a36Sopenharmony_ci		goto amacout;
176662306a36Sopenharmony_ci	}
176762306a36Sopenharmony_ci	ret = hex2bin(buf, obj->string.pointer + 9, 6);
176862306a36Sopenharmony_ci	if (!(ret == 0 && is_valid_ether_addr(buf))) {
176962306a36Sopenharmony_ci		netif_warn(tp, probe, tp->netdev,
177062306a36Sopenharmony_ci			   "Invalid MAC for pass-thru MAC addr: %d, %pM\n",
177162306a36Sopenharmony_ci			   ret, buf);
177262306a36Sopenharmony_ci		ret = -EINVAL;
177362306a36Sopenharmony_ci		goto amacout;
177462306a36Sopenharmony_ci	}
177562306a36Sopenharmony_ci	memcpy(sa->sa_data, buf, 6);
177662306a36Sopenharmony_ci	netif_info(tp, probe, tp->netdev,
177762306a36Sopenharmony_ci		   "Using pass-thru MAC addr %pM\n", sa->sa_data);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ciamacout:
178062306a36Sopenharmony_ci	kfree(obj);
178162306a36Sopenharmony_ci	return ret;
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic int determine_ethernet_addr(struct r8152 *tp, struct sockaddr *sa)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	struct net_device *dev = tp->netdev;
178762306a36Sopenharmony_ci	int ret;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	sa->sa_family = dev->type;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	ret = eth_platform_get_mac_address(&tp->udev->dev, sa->sa_data);
179262306a36Sopenharmony_ci	if (ret < 0) {
179362306a36Sopenharmony_ci		if (tp->version == RTL_VER_01) {
179462306a36Sopenharmony_ci			ret = pla_ocp_read(tp, PLA_IDR, 8, sa->sa_data);
179562306a36Sopenharmony_ci		} else {
179662306a36Sopenharmony_ci			/* if device doesn't support MAC pass through this will
179762306a36Sopenharmony_ci			 * be expected to be non-zero
179862306a36Sopenharmony_ci			 */
179962306a36Sopenharmony_ci			ret = vendor_mac_passthru_addr_read(tp, sa);
180062306a36Sopenharmony_ci			if (ret < 0)
180162306a36Sopenharmony_ci				ret = pla_ocp_read(tp, PLA_BACKUP, 8,
180262306a36Sopenharmony_ci						   sa->sa_data);
180362306a36Sopenharmony_ci		}
180462306a36Sopenharmony_ci	}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (ret < 0) {
180762306a36Sopenharmony_ci		netif_err(tp, probe, dev, "Get ether addr fail\n");
180862306a36Sopenharmony_ci	} else if (!is_valid_ether_addr(sa->sa_data)) {
180962306a36Sopenharmony_ci		netif_err(tp, probe, dev, "Invalid ether addr %pM\n",
181062306a36Sopenharmony_ci			  sa->sa_data);
181162306a36Sopenharmony_ci		eth_hw_addr_random(dev);
181262306a36Sopenharmony_ci		ether_addr_copy(sa->sa_data, dev->dev_addr);
181362306a36Sopenharmony_ci		netif_info(tp, probe, dev, "Random ether addr %pM\n",
181462306a36Sopenharmony_ci			   sa->sa_data);
181562306a36Sopenharmony_ci		return 0;
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	return ret;
181962306a36Sopenharmony_ci}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic int set_ethernet_addr(struct r8152 *tp, bool in_resume)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	struct net_device *dev = tp->netdev;
182462306a36Sopenharmony_ci	struct sockaddr sa;
182562306a36Sopenharmony_ci	int ret;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	ret = determine_ethernet_addr(tp, &sa);
182862306a36Sopenharmony_ci	if (ret < 0)
182962306a36Sopenharmony_ci		return ret;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	if (tp->version == RTL_VER_01)
183262306a36Sopenharmony_ci		eth_hw_addr_set(dev, sa.sa_data);
183362306a36Sopenharmony_ci	else
183462306a36Sopenharmony_ci		ret = __rtl8152_set_mac_address(dev, &sa, in_resume);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	return ret;
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_cistatic void read_bulk_callback(struct urb *urb)
184062306a36Sopenharmony_ci{
184162306a36Sopenharmony_ci	struct net_device *netdev;
184262306a36Sopenharmony_ci	int status = urb->status;
184362306a36Sopenharmony_ci	struct rx_agg *agg;
184462306a36Sopenharmony_ci	struct r8152 *tp;
184562306a36Sopenharmony_ci	unsigned long flags;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	agg = urb->context;
184862306a36Sopenharmony_ci	if (!agg)
184962306a36Sopenharmony_ci		return;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	tp = agg->context;
185262306a36Sopenharmony_ci	if (!tp)
185362306a36Sopenharmony_ci		return;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
185662306a36Sopenharmony_ci		return;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	if (!test_bit(WORK_ENABLE, &tp->flags))
185962306a36Sopenharmony_ci		return;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	netdev = tp->netdev;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/* When link down, the driver would cancel all bulks. */
186462306a36Sopenharmony_ci	/* This avoid the re-submitting bulk */
186562306a36Sopenharmony_ci	if (!netif_carrier_ok(netdev))
186662306a36Sopenharmony_ci		return;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	usb_mark_last_busy(tp->udev);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	switch (status) {
187162306a36Sopenharmony_ci	case 0:
187262306a36Sopenharmony_ci		if (urb->actual_length < ETH_ZLEN)
187362306a36Sopenharmony_ci			break;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci		spin_lock_irqsave(&tp->rx_lock, flags);
187662306a36Sopenharmony_ci		list_add_tail(&agg->list, &tp->rx_done);
187762306a36Sopenharmony_ci		spin_unlock_irqrestore(&tp->rx_lock, flags);
187862306a36Sopenharmony_ci		napi_schedule(&tp->napi);
187962306a36Sopenharmony_ci		return;
188062306a36Sopenharmony_ci	case -ESHUTDOWN:
188162306a36Sopenharmony_ci		rtl_set_unplug(tp);
188262306a36Sopenharmony_ci		netif_device_detach(tp->netdev);
188362306a36Sopenharmony_ci		return;
188462306a36Sopenharmony_ci	case -EPROTO:
188562306a36Sopenharmony_ci		urb->actual_length = 0;
188662306a36Sopenharmony_ci		spin_lock_irqsave(&tp->rx_lock, flags);
188762306a36Sopenharmony_ci		list_add_tail(&agg->list, &tp->rx_done);
188862306a36Sopenharmony_ci		spin_unlock_irqrestore(&tp->rx_lock, flags);
188962306a36Sopenharmony_ci		set_bit(RX_EPROTO, &tp->flags);
189062306a36Sopenharmony_ci		schedule_delayed_work(&tp->schedule, 1);
189162306a36Sopenharmony_ci		return;
189262306a36Sopenharmony_ci	case -ENOENT:
189362306a36Sopenharmony_ci		return;	/* the urb is in unlink state */
189462306a36Sopenharmony_ci	case -ETIME:
189562306a36Sopenharmony_ci		if (net_ratelimit())
189662306a36Sopenharmony_ci			netdev_warn(netdev, "maybe reset is needed?\n");
189762306a36Sopenharmony_ci		break;
189862306a36Sopenharmony_ci	default:
189962306a36Sopenharmony_ci		if (net_ratelimit())
190062306a36Sopenharmony_ci			netdev_warn(netdev, "Rx status %d\n", status);
190162306a36Sopenharmony_ci		break;
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	r8152_submit_rx(tp, agg, GFP_ATOMIC);
190562306a36Sopenharmony_ci}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_cistatic void write_bulk_callback(struct urb *urb)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	struct net_device_stats *stats;
191062306a36Sopenharmony_ci	struct net_device *netdev;
191162306a36Sopenharmony_ci	struct tx_agg *agg;
191262306a36Sopenharmony_ci	struct r8152 *tp;
191362306a36Sopenharmony_ci	unsigned long flags;
191462306a36Sopenharmony_ci	int status = urb->status;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	agg = urb->context;
191762306a36Sopenharmony_ci	if (!agg)
191862306a36Sopenharmony_ci		return;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	tp = agg->context;
192162306a36Sopenharmony_ci	if (!tp)
192262306a36Sopenharmony_ci		return;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	netdev = tp->netdev;
192562306a36Sopenharmony_ci	stats = &netdev->stats;
192662306a36Sopenharmony_ci	if (status) {
192762306a36Sopenharmony_ci		if (net_ratelimit())
192862306a36Sopenharmony_ci			netdev_warn(netdev, "Tx status %d\n", status);
192962306a36Sopenharmony_ci		stats->tx_errors += agg->skb_num;
193062306a36Sopenharmony_ci	} else {
193162306a36Sopenharmony_ci		stats->tx_packets += agg->skb_num;
193262306a36Sopenharmony_ci		stats->tx_bytes += agg->skb_len;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	spin_lock_irqsave(&tp->tx_lock, flags);
193662306a36Sopenharmony_ci	list_add_tail(&agg->list, &tp->tx_free);
193762306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->tx_lock, flags);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	usb_autopm_put_interface_async(tp->intf);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (!netif_carrier_ok(netdev))
194262306a36Sopenharmony_ci		return;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	if (!test_bit(WORK_ENABLE, &tp->flags))
194562306a36Sopenharmony_ci		return;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
194862306a36Sopenharmony_ci		return;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (!skb_queue_empty(&tp->tx_queue))
195162306a36Sopenharmony_ci		tasklet_schedule(&tp->tx_tl);
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_cistatic void intr_callback(struct urb *urb)
195562306a36Sopenharmony_ci{
195662306a36Sopenharmony_ci	struct r8152 *tp;
195762306a36Sopenharmony_ci	__le16 *d;
195862306a36Sopenharmony_ci	int status = urb->status;
195962306a36Sopenharmony_ci	int res;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	tp = urb->context;
196262306a36Sopenharmony_ci	if (!tp)
196362306a36Sopenharmony_ci		return;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (!test_bit(WORK_ENABLE, &tp->flags))
196662306a36Sopenharmony_ci		return;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
196962306a36Sopenharmony_ci		return;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	switch (status) {
197262306a36Sopenharmony_ci	case 0:			/* success */
197362306a36Sopenharmony_ci		break;
197462306a36Sopenharmony_ci	case -ECONNRESET:	/* unlink */
197562306a36Sopenharmony_ci	case -ESHUTDOWN:
197662306a36Sopenharmony_ci		netif_device_detach(tp->netdev);
197762306a36Sopenharmony_ci		fallthrough;
197862306a36Sopenharmony_ci	case -ENOENT:
197962306a36Sopenharmony_ci	case -EPROTO:
198062306a36Sopenharmony_ci		netif_info(tp, intr, tp->netdev,
198162306a36Sopenharmony_ci			   "Stop submitting intr, status %d\n", status);
198262306a36Sopenharmony_ci		return;
198362306a36Sopenharmony_ci	case -EOVERFLOW:
198462306a36Sopenharmony_ci		if (net_ratelimit())
198562306a36Sopenharmony_ci			netif_info(tp, intr, tp->netdev,
198662306a36Sopenharmony_ci				   "intr status -EOVERFLOW\n");
198762306a36Sopenharmony_ci		goto resubmit;
198862306a36Sopenharmony_ci	/* -EPIPE:  should clear the halt */
198962306a36Sopenharmony_ci	default:
199062306a36Sopenharmony_ci		netif_info(tp, intr, tp->netdev, "intr status %d\n", status);
199162306a36Sopenharmony_ci		goto resubmit;
199262306a36Sopenharmony_ci	}
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	d = urb->transfer_buffer;
199562306a36Sopenharmony_ci	if (INTR_LINK & __le16_to_cpu(d[0])) {
199662306a36Sopenharmony_ci		if (!netif_carrier_ok(tp->netdev)) {
199762306a36Sopenharmony_ci			set_bit(RTL8152_LINK_CHG, &tp->flags);
199862306a36Sopenharmony_ci			schedule_delayed_work(&tp->schedule, 0);
199962306a36Sopenharmony_ci		}
200062306a36Sopenharmony_ci	} else {
200162306a36Sopenharmony_ci		if (netif_carrier_ok(tp->netdev)) {
200262306a36Sopenharmony_ci			netif_stop_queue(tp->netdev);
200362306a36Sopenharmony_ci			set_bit(RTL8152_LINK_CHG, &tp->flags);
200462306a36Sopenharmony_ci			schedule_delayed_work(&tp->schedule, 0);
200562306a36Sopenharmony_ci		}
200662306a36Sopenharmony_ci	}
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ciresubmit:
200962306a36Sopenharmony_ci	res = usb_submit_urb(urb, GFP_ATOMIC);
201062306a36Sopenharmony_ci	if (res == -ENODEV) {
201162306a36Sopenharmony_ci		rtl_set_unplug(tp);
201262306a36Sopenharmony_ci		netif_device_detach(tp->netdev);
201362306a36Sopenharmony_ci	} else if (res) {
201462306a36Sopenharmony_ci		netif_err(tp, intr, tp->netdev,
201562306a36Sopenharmony_ci			  "can't resubmit intr, status %d\n", res);
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_cistatic inline void *rx_agg_align(void *data)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	return (void *)ALIGN((uintptr_t)data, RX_ALIGN);
202262306a36Sopenharmony_ci}
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_cistatic inline void *tx_agg_align(void *data)
202562306a36Sopenharmony_ci{
202662306a36Sopenharmony_ci	return (void *)ALIGN((uintptr_t)data, TX_ALIGN);
202762306a36Sopenharmony_ci}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic void free_rx_agg(struct r8152 *tp, struct rx_agg *agg)
203062306a36Sopenharmony_ci{
203162306a36Sopenharmony_ci	list_del(&agg->info_list);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	usb_free_urb(agg->urb);
203462306a36Sopenharmony_ci	put_page(agg->page);
203562306a36Sopenharmony_ci	kfree(agg);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	atomic_dec(&tp->rx_count);
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_cistatic struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
204362306a36Sopenharmony_ci	int node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
204462306a36Sopenharmony_ci	unsigned int order = get_order(tp->rx_buf_sz);
204562306a36Sopenharmony_ci	struct rx_agg *rx_agg;
204662306a36Sopenharmony_ci	unsigned long flags;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	rx_agg = kmalloc_node(sizeof(*rx_agg), mflags, node);
204962306a36Sopenharmony_ci	if (!rx_agg)
205062306a36Sopenharmony_ci		return NULL;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	rx_agg->page = alloc_pages(mflags | __GFP_COMP | __GFP_NOWARN, order);
205362306a36Sopenharmony_ci	if (!rx_agg->page)
205462306a36Sopenharmony_ci		goto free_rx;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	rx_agg->buffer = page_address(rx_agg->page);
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	rx_agg->urb = usb_alloc_urb(0, mflags);
205962306a36Sopenharmony_ci	if (!rx_agg->urb)
206062306a36Sopenharmony_ci		goto free_buf;
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	rx_agg->context = tp;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	INIT_LIST_HEAD(&rx_agg->list);
206562306a36Sopenharmony_ci	INIT_LIST_HEAD(&rx_agg->info_list);
206662306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
206762306a36Sopenharmony_ci	list_add_tail(&rx_agg->info_list, &tp->rx_info);
206862306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	atomic_inc(&tp->rx_count);
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	return rx_agg;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cifree_buf:
207562306a36Sopenharmony_ci	__free_pages(rx_agg->page, order);
207662306a36Sopenharmony_cifree_rx:
207762306a36Sopenharmony_ci	kfree(rx_agg);
207862306a36Sopenharmony_ci	return NULL;
207962306a36Sopenharmony_ci}
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_cistatic void free_all_mem(struct r8152 *tp)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	struct rx_agg *agg, *agg_next;
208462306a36Sopenharmony_ci	unsigned long flags;
208562306a36Sopenharmony_ci	int i;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	list_for_each_entry_safe(agg, agg_next, &tp->rx_info, info_list)
209062306a36Sopenharmony_ci		free_rx_agg(tp, agg);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	WARN_ON(atomic_read(&tp->rx_count));
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	for (i = 0; i < RTL8152_MAX_TX; i++) {
209762306a36Sopenharmony_ci		usb_free_urb(tp->tx_info[i].urb);
209862306a36Sopenharmony_ci		tp->tx_info[i].urb = NULL;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci		kfree(tp->tx_info[i].buffer);
210162306a36Sopenharmony_ci		tp->tx_info[i].buffer = NULL;
210262306a36Sopenharmony_ci		tp->tx_info[i].head = NULL;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	usb_free_urb(tp->intr_urb);
210662306a36Sopenharmony_ci	tp->intr_urb = NULL;
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	kfree(tp->intr_buff);
210962306a36Sopenharmony_ci	tp->intr_buff = NULL;
211062306a36Sopenharmony_ci}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_cistatic int alloc_all_mem(struct r8152 *tp)
211362306a36Sopenharmony_ci{
211462306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
211562306a36Sopenharmony_ci	struct usb_interface *intf = tp->intf;
211662306a36Sopenharmony_ci	struct usb_host_interface *alt = intf->cur_altsetting;
211762306a36Sopenharmony_ci	struct usb_host_endpoint *ep_intr = alt->endpoint + 2;
211862306a36Sopenharmony_ci	int node, i;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	spin_lock_init(&tp->rx_lock);
212362306a36Sopenharmony_ci	spin_lock_init(&tp->tx_lock);
212462306a36Sopenharmony_ci	INIT_LIST_HEAD(&tp->rx_info);
212562306a36Sopenharmony_ci	INIT_LIST_HEAD(&tp->tx_free);
212662306a36Sopenharmony_ci	INIT_LIST_HEAD(&tp->rx_done);
212762306a36Sopenharmony_ci	skb_queue_head_init(&tp->tx_queue);
212862306a36Sopenharmony_ci	skb_queue_head_init(&tp->rx_queue);
212962306a36Sopenharmony_ci	atomic_set(&tp->rx_count, 0);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	for (i = 0; i < RTL8152_MAX_RX; i++) {
213262306a36Sopenharmony_ci		if (!alloc_rx_agg(tp, GFP_KERNEL))
213362306a36Sopenharmony_ci			goto err1;
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	for (i = 0; i < RTL8152_MAX_TX; i++) {
213762306a36Sopenharmony_ci		struct urb *urb;
213862306a36Sopenharmony_ci		u8 *buf;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci		buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
214162306a36Sopenharmony_ci		if (!buf)
214262306a36Sopenharmony_ci			goto err1;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		if (buf != tx_agg_align(buf)) {
214562306a36Sopenharmony_ci			kfree(buf);
214662306a36Sopenharmony_ci			buf = kmalloc_node(agg_buf_sz + TX_ALIGN, GFP_KERNEL,
214762306a36Sopenharmony_ci					   node);
214862306a36Sopenharmony_ci			if (!buf)
214962306a36Sopenharmony_ci				goto err1;
215062306a36Sopenharmony_ci		}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci		urb = usb_alloc_urb(0, GFP_KERNEL);
215362306a36Sopenharmony_ci		if (!urb) {
215462306a36Sopenharmony_ci			kfree(buf);
215562306a36Sopenharmony_ci			goto err1;
215662306a36Sopenharmony_ci		}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci		INIT_LIST_HEAD(&tp->tx_info[i].list);
215962306a36Sopenharmony_ci		tp->tx_info[i].context = tp;
216062306a36Sopenharmony_ci		tp->tx_info[i].urb = urb;
216162306a36Sopenharmony_ci		tp->tx_info[i].buffer = buf;
216262306a36Sopenharmony_ci		tp->tx_info[i].head = tx_agg_align(buf);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		list_add_tail(&tp->tx_info[i].list, &tp->tx_free);
216562306a36Sopenharmony_ci	}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
216862306a36Sopenharmony_ci	if (!tp->intr_urb)
216962306a36Sopenharmony_ci		goto err1;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
217262306a36Sopenharmony_ci	if (!tp->intr_buff)
217362306a36Sopenharmony_ci		goto err1;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	tp->intr_interval = (int)ep_intr->desc.bInterval;
217662306a36Sopenharmony_ci	usb_fill_int_urb(tp->intr_urb, tp->udev, tp->pipe_intr,
217762306a36Sopenharmony_ci			 tp->intr_buff, INTBUFSIZE, intr_callback,
217862306a36Sopenharmony_ci			 tp, tp->intr_interval);
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	return 0;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_cierr1:
218362306a36Sopenharmony_ci	free_all_mem(tp);
218462306a36Sopenharmony_ci	return -ENOMEM;
218562306a36Sopenharmony_ci}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_cistatic struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
218862306a36Sopenharmony_ci{
218962306a36Sopenharmony_ci	struct tx_agg *agg = NULL;
219062306a36Sopenharmony_ci	unsigned long flags;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if (list_empty(&tp->tx_free))
219362306a36Sopenharmony_ci		return NULL;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	spin_lock_irqsave(&tp->tx_lock, flags);
219662306a36Sopenharmony_ci	if (!list_empty(&tp->tx_free)) {
219762306a36Sopenharmony_ci		struct list_head *cursor;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci		cursor = tp->tx_free.next;
220062306a36Sopenharmony_ci		list_del_init(cursor);
220162306a36Sopenharmony_ci		agg = list_entry(cursor, struct tx_agg, list);
220262306a36Sopenharmony_ci	}
220362306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->tx_lock, flags);
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	return agg;
220662306a36Sopenharmony_ci}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci/* r8152_csum_workaround()
220962306a36Sopenharmony_ci * The hw limits the value of the transport offset. When the offset is out of
221062306a36Sopenharmony_ci * range, calculate the checksum by sw.
221162306a36Sopenharmony_ci */
221262306a36Sopenharmony_cistatic void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
221362306a36Sopenharmony_ci				  struct sk_buff_head *list)
221462306a36Sopenharmony_ci{
221562306a36Sopenharmony_ci	if (skb_shinfo(skb)->gso_size) {
221662306a36Sopenharmony_ci		netdev_features_t features = tp->netdev->features;
221762306a36Sopenharmony_ci		struct sk_buff *segs, *seg, *next;
221862306a36Sopenharmony_ci		struct sk_buff_head seg_list;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci		features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
222162306a36Sopenharmony_ci		segs = skb_gso_segment(skb, features);
222262306a36Sopenharmony_ci		if (IS_ERR(segs) || !segs)
222362306a36Sopenharmony_ci			goto drop;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci		__skb_queue_head_init(&seg_list);
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci		skb_list_walk_safe(segs, seg, next) {
222862306a36Sopenharmony_ci			skb_mark_not_on_list(seg);
222962306a36Sopenharmony_ci			__skb_queue_tail(&seg_list, seg);
223062306a36Sopenharmony_ci		}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci		skb_queue_splice(&seg_list, list);
223362306a36Sopenharmony_ci		dev_kfree_skb(skb);
223462306a36Sopenharmony_ci	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
223562306a36Sopenharmony_ci		if (skb_checksum_help(skb) < 0)
223662306a36Sopenharmony_ci			goto drop;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci		__skb_queue_head(list, skb);
223962306a36Sopenharmony_ci	} else {
224062306a36Sopenharmony_ci		struct net_device_stats *stats;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_cidrop:
224362306a36Sopenharmony_ci		stats = &tp->netdev->stats;
224462306a36Sopenharmony_ci		stats->tx_dropped++;
224562306a36Sopenharmony_ci		dev_kfree_skb(skb);
224662306a36Sopenharmony_ci	}
224762306a36Sopenharmony_ci}
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_cistatic inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb)
225062306a36Sopenharmony_ci{
225162306a36Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
225262306a36Sopenharmony_ci		u32 opts2;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci		opts2 = TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb));
225562306a36Sopenharmony_ci		desc->opts2 |= cpu_to_le32(opts2);
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci}
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_cistatic inline void rtl_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb)
226062306a36Sopenharmony_ci{
226162306a36Sopenharmony_ci	u32 opts2 = le32_to_cpu(desc->opts2);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	if (opts2 & RX_VLAN_TAG)
226462306a36Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
226562306a36Sopenharmony_ci				       swab16(opts2 & 0xffff));
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
226962306a36Sopenharmony_ci			 struct sk_buff *skb, u32 len)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	u32 mss = skb_shinfo(skb)->gso_size;
227262306a36Sopenharmony_ci	u32 opts1, opts2 = 0;
227362306a36Sopenharmony_ci	int ret = TX_CSUM_SUCCESS;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	WARN_ON_ONCE(len > TX_LEN_MAX);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	opts1 = len | TX_FS | TX_LS;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	if (mss) {
228062306a36Sopenharmony_ci		u32 transport_offset = (u32)skb_transport_offset(skb);
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci		if (transport_offset > GTTCPHO_MAX) {
228362306a36Sopenharmony_ci			netif_warn(tp, tx_err, tp->netdev,
228462306a36Sopenharmony_ci				   "Invalid transport offset 0x%x for TSO\n",
228562306a36Sopenharmony_ci				   transport_offset);
228662306a36Sopenharmony_ci			ret = TX_CSUM_TSO;
228762306a36Sopenharmony_ci			goto unavailable;
228862306a36Sopenharmony_ci		}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci		switch (vlan_get_protocol(skb)) {
229162306a36Sopenharmony_ci		case htons(ETH_P_IP):
229262306a36Sopenharmony_ci			opts1 |= GTSENDV4;
229362306a36Sopenharmony_ci			break;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci		case htons(ETH_P_IPV6):
229662306a36Sopenharmony_ci			if (skb_cow_head(skb, 0)) {
229762306a36Sopenharmony_ci				ret = TX_CSUM_TSO;
229862306a36Sopenharmony_ci				goto unavailable;
229962306a36Sopenharmony_ci			}
230062306a36Sopenharmony_ci			tcp_v6_gso_csum_prep(skb);
230162306a36Sopenharmony_ci			opts1 |= GTSENDV6;
230262306a36Sopenharmony_ci			break;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci		default:
230562306a36Sopenharmony_ci			WARN_ON_ONCE(1);
230662306a36Sopenharmony_ci			break;
230762306a36Sopenharmony_ci		}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci		opts1 |= transport_offset << GTTCPHO_SHIFT;
231062306a36Sopenharmony_ci		opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
231162306a36Sopenharmony_ci	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
231262306a36Sopenharmony_ci		u32 transport_offset = (u32)skb_transport_offset(skb);
231362306a36Sopenharmony_ci		u8 ip_protocol;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci		if (transport_offset > TCPHO_MAX) {
231662306a36Sopenharmony_ci			netif_warn(tp, tx_err, tp->netdev,
231762306a36Sopenharmony_ci				   "Invalid transport offset 0x%x\n",
231862306a36Sopenharmony_ci				   transport_offset);
231962306a36Sopenharmony_ci			ret = TX_CSUM_NONE;
232062306a36Sopenharmony_ci			goto unavailable;
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci		switch (vlan_get_protocol(skb)) {
232462306a36Sopenharmony_ci		case htons(ETH_P_IP):
232562306a36Sopenharmony_ci			opts2 |= IPV4_CS;
232662306a36Sopenharmony_ci			ip_protocol = ip_hdr(skb)->protocol;
232762306a36Sopenharmony_ci			break;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		case htons(ETH_P_IPV6):
233062306a36Sopenharmony_ci			opts2 |= IPV6_CS;
233162306a36Sopenharmony_ci			ip_protocol = ipv6_hdr(skb)->nexthdr;
233262306a36Sopenharmony_ci			break;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci		default:
233562306a36Sopenharmony_ci			ip_protocol = IPPROTO_RAW;
233662306a36Sopenharmony_ci			break;
233762306a36Sopenharmony_ci		}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci		if (ip_protocol == IPPROTO_TCP)
234062306a36Sopenharmony_ci			opts2 |= TCP_CS;
234162306a36Sopenharmony_ci		else if (ip_protocol == IPPROTO_UDP)
234262306a36Sopenharmony_ci			opts2 |= UDP_CS;
234362306a36Sopenharmony_ci		else
234462306a36Sopenharmony_ci			WARN_ON_ONCE(1);
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci		opts2 |= transport_offset << TCPHO_SHIFT;
234762306a36Sopenharmony_ci	}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	desc->opts2 = cpu_to_le32(opts2);
235062306a36Sopenharmony_ci	desc->opts1 = cpu_to_le32(opts1);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ciunavailable:
235362306a36Sopenharmony_ci	return ret;
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_cistatic int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
235762306a36Sopenharmony_ci{
235862306a36Sopenharmony_ci	struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
235962306a36Sopenharmony_ci	int remain, ret;
236062306a36Sopenharmony_ci	u8 *tx_data;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	__skb_queue_head_init(&skb_head);
236362306a36Sopenharmony_ci	spin_lock(&tx_queue->lock);
236462306a36Sopenharmony_ci	skb_queue_splice_init(tx_queue, &skb_head);
236562306a36Sopenharmony_ci	spin_unlock(&tx_queue->lock);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	tx_data = agg->head;
236862306a36Sopenharmony_ci	agg->skb_num = 0;
236962306a36Sopenharmony_ci	agg->skb_len = 0;
237062306a36Sopenharmony_ci	remain = agg_buf_sz;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
237362306a36Sopenharmony_ci		struct tx_desc *tx_desc;
237462306a36Sopenharmony_ci		struct sk_buff *skb;
237562306a36Sopenharmony_ci		unsigned int len;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci		skb = __skb_dequeue(&skb_head);
237862306a36Sopenharmony_ci		if (!skb)
237962306a36Sopenharmony_ci			break;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		len = skb->len + sizeof(*tx_desc);
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci		if (len > remain) {
238462306a36Sopenharmony_ci			__skb_queue_head(&skb_head, skb);
238562306a36Sopenharmony_ci			break;
238662306a36Sopenharmony_ci		}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci		tx_data = tx_agg_align(tx_data);
238962306a36Sopenharmony_ci		tx_desc = (struct tx_desc *)tx_data;
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci		if (r8152_tx_csum(tp, tx_desc, skb, skb->len)) {
239262306a36Sopenharmony_ci			r8152_csum_workaround(tp, skb, &skb_head);
239362306a36Sopenharmony_ci			continue;
239462306a36Sopenharmony_ci		}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci		rtl_tx_vlan_tag(tx_desc, skb);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci		tx_data += sizeof(*tx_desc);
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci		len = skb->len;
240162306a36Sopenharmony_ci		if (skb_copy_bits(skb, 0, tx_data, len) < 0) {
240262306a36Sopenharmony_ci			struct net_device_stats *stats = &tp->netdev->stats;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci			stats->tx_dropped++;
240562306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
240662306a36Sopenharmony_ci			tx_data -= sizeof(*tx_desc);
240762306a36Sopenharmony_ci			continue;
240862306a36Sopenharmony_ci		}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci		tx_data += len;
241162306a36Sopenharmony_ci		agg->skb_len += len;
241262306a36Sopenharmony_ci		agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci		remain = agg_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci		if (tp->dell_tb_rx_agg_bug)
241962306a36Sopenharmony_ci			break;
242062306a36Sopenharmony_ci	}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	if (!skb_queue_empty(&skb_head)) {
242362306a36Sopenharmony_ci		spin_lock(&tx_queue->lock);
242462306a36Sopenharmony_ci		skb_queue_splice(&skb_head, tx_queue);
242562306a36Sopenharmony_ci		spin_unlock(&tx_queue->lock);
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	netif_tx_lock(tp->netdev);
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	if (netif_queue_stopped(tp->netdev) &&
243162306a36Sopenharmony_ci	    skb_queue_len(&tp->tx_queue) < tp->tx_qlen)
243262306a36Sopenharmony_ci		netif_wake_queue(tp->netdev);
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	netif_tx_unlock(tp->netdev);
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	ret = usb_autopm_get_interface_async(tp->intf);
243762306a36Sopenharmony_ci	if (ret < 0)
243862306a36Sopenharmony_ci		goto out_tx_fill;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	usb_fill_bulk_urb(agg->urb, tp->udev, tp->pipe_out,
244162306a36Sopenharmony_ci			  agg->head, (int)(tx_data - (u8 *)agg->head),
244262306a36Sopenharmony_ci			  (usb_complete_t)write_bulk_callback, agg);
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	ret = usb_submit_urb(agg->urb, GFP_ATOMIC);
244562306a36Sopenharmony_ci	if (ret < 0)
244662306a36Sopenharmony_ci		usb_autopm_put_interface_async(tp->intf);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ciout_tx_fill:
244962306a36Sopenharmony_ci	return ret;
245062306a36Sopenharmony_ci}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_cistatic u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
245362306a36Sopenharmony_ci{
245462306a36Sopenharmony_ci	u8 checksum = CHECKSUM_NONE;
245562306a36Sopenharmony_ci	u32 opts2, opts3;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	if (!(tp->netdev->features & NETIF_F_RXCSUM))
245862306a36Sopenharmony_ci		goto return_result;
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	opts2 = le32_to_cpu(rx_desc->opts2);
246162306a36Sopenharmony_ci	opts3 = le32_to_cpu(rx_desc->opts3);
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	if (opts2 & RD_IPV4_CS) {
246462306a36Sopenharmony_ci		if (opts3 & IPF)
246562306a36Sopenharmony_ci			checksum = CHECKSUM_NONE;
246662306a36Sopenharmony_ci		else if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
246762306a36Sopenharmony_ci			checksum = CHECKSUM_UNNECESSARY;
246862306a36Sopenharmony_ci		else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
246962306a36Sopenharmony_ci			checksum = CHECKSUM_UNNECESSARY;
247062306a36Sopenharmony_ci	} else if (opts2 & RD_IPV6_CS) {
247162306a36Sopenharmony_ci		if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
247262306a36Sopenharmony_ci			checksum = CHECKSUM_UNNECESSARY;
247362306a36Sopenharmony_ci		else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
247462306a36Sopenharmony_ci			checksum = CHECKSUM_UNNECESSARY;
247562306a36Sopenharmony_ci	}
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_cireturn_result:
247862306a36Sopenharmony_ci	return checksum;
247962306a36Sopenharmony_ci}
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_cistatic inline bool rx_count_exceed(struct r8152 *tp)
248262306a36Sopenharmony_ci{
248362306a36Sopenharmony_ci	return atomic_read(&tp->rx_count) > RTL8152_MAX_RX;
248462306a36Sopenharmony_ci}
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_cistatic inline int agg_offset(struct rx_agg *agg, void *addr)
248762306a36Sopenharmony_ci{
248862306a36Sopenharmony_ci	return (int)(addr - agg->buffer);
248962306a36Sopenharmony_ci}
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_cistatic struct rx_agg *rtl_get_free_rx(struct r8152 *tp, gfp_t mflags)
249262306a36Sopenharmony_ci{
249362306a36Sopenharmony_ci	struct rx_agg *agg, *agg_next, *agg_free = NULL;
249462306a36Sopenharmony_ci	unsigned long flags;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	list_for_each_entry_safe(agg, agg_next, &tp->rx_used, list) {
249962306a36Sopenharmony_ci		if (page_count(agg->page) == 1) {
250062306a36Sopenharmony_ci			if (!agg_free) {
250162306a36Sopenharmony_ci				list_del_init(&agg->list);
250262306a36Sopenharmony_ci				agg_free = agg;
250362306a36Sopenharmony_ci				continue;
250462306a36Sopenharmony_ci			}
250562306a36Sopenharmony_ci			if (rx_count_exceed(tp)) {
250662306a36Sopenharmony_ci				list_del_init(&agg->list);
250762306a36Sopenharmony_ci				free_rx_agg(tp, agg);
250862306a36Sopenharmony_ci			}
250962306a36Sopenharmony_ci			break;
251062306a36Sopenharmony_ci		}
251162306a36Sopenharmony_ci	}
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	if (!agg_free && atomic_read(&tp->rx_count) < tp->rx_pending)
251662306a36Sopenharmony_ci		agg_free = alloc_rx_agg(tp, mflags);
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	return agg_free;
251962306a36Sopenharmony_ci}
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_cistatic int rx_bottom(struct r8152 *tp, int budget)
252262306a36Sopenharmony_ci{
252362306a36Sopenharmony_ci	unsigned long flags;
252462306a36Sopenharmony_ci	struct list_head *cursor, *next, rx_queue;
252562306a36Sopenharmony_ci	int ret = 0, work_done = 0;
252662306a36Sopenharmony_ci	struct napi_struct *napi = &tp->napi;
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	if (!skb_queue_empty(&tp->rx_queue)) {
252962306a36Sopenharmony_ci		while (work_done < budget) {
253062306a36Sopenharmony_ci			struct sk_buff *skb = __skb_dequeue(&tp->rx_queue);
253162306a36Sopenharmony_ci			struct net_device *netdev = tp->netdev;
253262306a36Sopenharmony_ci			struct net_device_stats *stats = &netdev->stats;
253362306a36Sopenharmony_ci			unsigned int pkt_len;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci			if (!skb)
253662306a36Sopenharmony_ci				break;
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci			pkt_len = skb->len;
253962306a36Sopenharmony_ci			napi_gro_receive(napi, skb);
254062306a36Sopenharmony_ci			work_done++;
254162306a36Sopenharmony_ci			stats->rx_packets++;
254262306a36Sopenharmony_ci			stats->rx_bytes += pkt_len;
254362306a36Sopenharmony_ci		}
254462306a36Sopenharmony_ci	}
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	if (list_empty(&tp->rx_done) || work_done >= budget)
254762306a36Sopenharmony_ci		goto out1;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	clear_bit(RX_EPROTO, &tp->flags);
255062306a36Sopenharmony_ci	INIT_LIST_HEAD(&rx_queue);
255162306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
255262306a36Sopenharmony_ci	list_splice_init(&tp->rx_done, &rx_queue);
255362306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	list_for_each_safe(cursor, next, &rx_queue) {
255662306a36Sopenharmony_ci		struct rx_desc *rx_desc;
255762306a36Sopenharmony_ci		struct rx_agg *agg, *agg_free;
255862306a36Sopenharmony_ci		int len_used = 0;
255962306a36Sopenharmony_ci		struct urb *urb;
256062306a36Sopenharmony_ci		u8 *rx_data;
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci		/* A bulk transfer of USB may contain may packets, so the
256362306a36Sopenharmony_ci		 * total packets may more than the budget. Deal with all
256462306a36Sopenharmony_ci		 * packets in current bulk transfer, and stop to handle the
256562306a36Sopenharmony_ci		 * next bulk transfer until next schedule, if budget is
256662306a36Sopenharmony_ci		 * exhausted.
256762306a36Sopenharmony_ci		 */
256862306a36Sopenharmony_ci		if (work_done >= budget)
256962306a36Sopenharmony_ci			break;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci		list_del_init(cursor);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci		agg = list_entry(cursor, struct rx_agg, list);
257462306a36Sopenharmony_ci		urb = agg->urb;
257562306a36Sopenharmony_ci		if (urb->status != 0 || urb->actual_length < ETH_ZLEN)
257662306a36Sopenharmony_ci			goto submit;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci		agg_free = rtl_get_free_rx(tp, GFP_ATOMIC);
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci		rx_desc = agg->buffer;
258162306a36Sopenharmony_ci		rx_data = agg->buffer;
258262306a36Sopenharmony_ci		len_used += sizeof(struct rx_desc);
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci		while (urb->actual_length > len_used) {
258562306a36Sopenharmony_ci			struct net_device *netdev = tp->netdev;
258662306a36Sopenharmony_ci			struct net_device_stats *stats = &netdev->stats;
258762306a36Sopenharmony_ci			unsigned int pkt_len, rx_frag_head_sz;
258862306a36Sopenharmony_ci			struct sk_buff *skb;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci			WARN_ON_ONCE(skb_queue_len(&tp->rx_queue) >= 1000);
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci			pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
259362306a36Sopenharmony_ci			if (pkt_len < ETH_ZLEN)
259462306a36Sopenharmony_ci				break;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci			len_used += pkt_len;
259762306a36Sopenharmony_ci			if (urb->actual_length < len_used)
259862306a36Sopenharmony_ci				break;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci			pkt_len -= ETH_FCS_LEN;
260162306a36Sopenharmony_ci			rx_data += sizeof(struct rx_desc);
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci			if (!agg_free || tp->rx_copybreak > pkt_len)
260462306a36Sopenharmony_ci				rx_frag_head_sz = pkt_len;
260562306a36Sopenharmony_ci			else
260662306a36Sopenharmony_ci				rx_frag_head_sz = tp->rx_copybreak;
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci			skb = napi_alloc_skb(napi, rx_frag_head_sz);
260962306a36Sopenharmony_ci			if (!skb) {
261062306a36Sopenharmony_ci				stats->rx_dropped++;
261162306a36Sopenharmony_ci				goto find_next_rx;
261262306a36Sopenharmony_ci			}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci			skb->ip_summed = r8152_rx_csum(tp, rx_desc);
261562306a36Sopenharmony_ci			memcpy(skb->data, rx_data, rx_frag_head_sz);
261662306a36Sopenharmony_ci			skb_put(skb, rx_frag_head_sz);
261762306a36Sopenharmony_ci			pkt_len -= rx_frag_head_sz;
261862306a36Sopenharmony_ci			rx_data += rx_frag_head_sz;
261962306a36Sopenharmony_ci			if (pkt_len) {
262062306a36Sopenharmony_ci				skb_add_rx_frag(skb, 0, agg->page,
262162306a36Sopenharmony_ci						agg_offset(agg, rx_data),
262262306a36Sopenharmony_ci						pkt_len,
262362306a36Sopenharmony_ci						SKB_DATA_ALIGN(pkt_len));
262462306a36Sopenharmony_ci				get_page(agg->page);
262562306a36Sopenharmony_ci			}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, netdev);
262862306a36Sopenharmony_ci			rtl_rx_vlan_tag(rx_desc, skb);
262962306a36Sopenharmony_ci			if (work_done < budget) {
263062306a36Sopenharmony_ci				work_done++;
263162306a36Sopenharmony_ci				stats->rx_packets++;
263262306a36Sopenharmony_ci				stats->rx_bytes += skb->len;
263362306a36Sopenharmony_ci				napi_gro_receive(napi, skb);
263462306a36Sopenharmony_ci			} else {
263562306a36Sopenharmony_ci				__skb_queue_tail(&tp->rx_queue, skb);
263662306a36Sopenharmony_ci			}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_cifind_next_rx:
263962306a36Sopenharmony_ci			rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN);
264062306a36Sopenharmony_ci			rx_desc = (struct rx_desc *)rx_data;
264162306a36Sopenharmony_ci			len_used = agg_offset(agg, rx_data);
264262306a36Sopenharmony_ci			len_used += sizeof(struct rx_desc);
264362306a36Sopenharmony_ci		}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci		WARN_ON(!agg_free && page_count(agg->page) > 1);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci		if (agg_free) {
264862306a36Sopenharmony_ci			spin_lock_irqsave(&tp->rx_lock, flags);
264962306a36Sopenharmony_ci			if (page_count(agg->page) == 1) {
265062306a36Sopenharmony_ci				list_add(&agg_free->list, &tp->rx_used);
265162306a36Sopenharmony_ci			} else {
265262306a36Sopenharmony_ci				list_add_tail(&agg->list, &tp->rx_used);
265362306a36Sopenharmony_ci				agg = agg_free;
265462306a36Sopenharmony_ci				urb = agg->urb;
265562306a36Sopenharmony_ci			}
265662306a36Sopenharmony_ci			spin_unlock_irqrestore(&tp->rx_lock, flags);
265762306a36Sopenharmony_ci		}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_cisubmit:
266062306a36Sopenharmony_ci		if (!ret) {
266162306a36Sopenharmony_ci			ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
266262306a36Sopenharmony_ci		} else {
266362306a36Sopenharmony_ci			urb->actual_length = 0;
266462306a36Sopenharmony_ci			list_add_tail(&agg->list, next);
266562306a36Sopenharmony_ci		}
266662306a36Sopenharmony_ci	}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	/* Splice the remained list back to rx_done for next schedule */
266962306a36Sopenharmony_ci	if (!list_empty(&rx_queue)) {
267062306a36Sopenharmony_ci		spin_lock_irqsave(&tp->rx_lock, flags);
267162306a36Sopenharmony_ci		list_splice(&rx_queue, &tp->rx_done);
267262306a36Sopenharmony_ci		spin_unlock_irqrestore(&tp->rx_lock, flags);
267362306a36Sopenharmony_ci	}
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ciout1:
267662306a36Sopenharmony_ci	return work_done;
267762306a36Sopenharmony_ci}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_cistatic void tx_bottom(struct r8152 *tp)
268062306a36Sopenharmony_ci{
268162306a36Sopenharmony_ci	int res;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	do {
268462306a36Sopenharmony_ci		struct net_device *netdev = tp->netdev;
268562306a36Sopenharmony_ci		struct tx_agg *agg;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci		if (skb_queue_empty(&tp->tx_queue))
268862306a36Sopenharmony_ci			break;
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci		agg = r8152_get_tx_agg(tp);
269162306a36Sopenharmony_ci		if (!agg)
269262306a36Sopenharmony_ci			break;
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci		res = r8152_tx_agg_fill(tp, agg);
269562306a36Sopenharmony_ci		if (!res)
269662306a36Sopenharmony_ci			continue;
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci		if (res == -ENODEV) {
269962306a36Sopenharmony_ci			rtl_set_unplug(tp);
270062306a36Sopenharmony_ci			netif_device_detach(netdev);
270162306a36Sopenharmony_ci		} else {
270262306a36Sopenharmony_ci			struct net_device_stats *stats = &netdev->stats;
270362306a36Sopenharmony_ci			unsigned long flags;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci			netif_warn(tp, tx_err, netdev,
270662306a36Sopenharmony_ci				   "failed tx_urb %d\n", res);
270762306a36Sopenharmony_ci			stats->tx_dropped += agg->skb_num;
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci			spin_lock_irqsave(&tp->tx_lock, flags);
271062306a36Sopenharmony_ci			list_add_tail(&agg->list, &tp->tx_free);
271162306a36Sopenharmony_ci			spin_unlock_irqrestore(&tp->tx_lock, flags);
271262306a36Sopenharmony_ci		}
271362306a36Sopenharmony_ci	} while (res == 0);
271462306a36Sopenharmony_ci}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_cistatic void bottom_half(struct tasklet_struct *t)
271762306a36Sopenharmony_ci{
271862306a36Sopenharmony_ci	struct r8152 *tp = from_tasklet(tp, t, tx_tl);
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
272162306a36Sopenharmony_ci		return;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (!test_bit(WORK_ENABLE, &tp->flags))
272462306a36Sopenharmony_ci		return;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	/* When link down, the driver would cancel all bulks. */
272762306a36Sopenharmony_ci	/* This avoid the re-submitting bulk */
272862306a36Sopenharmony_ci	if (!netif_carrier_ok(tp->netdev))
272962306a36Sopenharmony_ci		return;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	clear_bit(SCHEDULE_TASKLET, &tp->flags);
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	tx_bottom(tp);
273462306a36Sopenharmony_ci}
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_cistatic int r8152_poll(struct napi_struct *napi, int budget)
273762306a36Sopenharmony_ci{
273862306a36Sopenharmony_ci	struct r8152 *tp = container_of(napi, struct r8152, napi);
273962306a36Sopenharmony_ci	int work_done;
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	if (!budget)
274262306a36Sopenharmony_ci		return 0;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	work_done = rx_bottom(tp, budget);
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	if (work_done < budget) {
274762306a36Sopenharmony_ci		if (!napi_complete_done(napi, work_done))
274862306a36Sopenharmony_ci			goto out;
274962306a36Sopenharmony_ci		if (!list_empty(&tp->rx_done))
275062306a36Sopenharmony_ci			napi_schedule(napi);
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ciout:
275462306a36Sopenharmony_ci	return work_done;
275562306a36Sopenharmony_ci}
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_cistatic
275862306a36Sopenharmony_ciint r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
275962306a36Sopenharmony_ci{
276062306a36Sopenharmony_ci	int ret;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	/* The rx would be stopped, so skip submitting */
276362306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags) ||
276462306a36Sopenharmony_ci	    !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev))
276562306a36Sopenharmony_ci		return 0;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	usb_fill_bulk_urb(agg->urb, tp->udev, tp->pipe_in,
276862306a36Sopenharmony_ci			  agg->buffer, tp->rx_buf_sz,
276962306a36Sopenharmony_ci			  (usb_complete_t)read_bulk_callback, agg);
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	ret = usb_submit_urb(agg->urb, mem_flags);
277262306a36Sopenharmony_ci	if (ret == -ENODEV) {
277362306a36Sopenharmony_ci		rtl_set_unplug(tp);
277462306a36Sopenharmony_ci		netif_device_detach(tp->netdev);
277562306a36Sopenharmony_ci	} else if (ret) {
277662306a36Sopenharmony_ci		struct urb *urb = agg->urb;
277762306a36Sopenharmony_ci		unsigned long flags;
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci		urb->actual_length = 0;
278062306a36Sopenharmony_ci		spin_lock_irqsave(&tp->rx_lock, flags);
278162306a36Sopenharmony_ci		list_add_tail(&agg->list, &tp->rx_done);
278262306a36Sopenharmony_ci		spin_unlock_irqrestore(&tp->rx_lock, flags);
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci		netif_err(tp, rx_err, tp->netdev,
278562306a36Sopenharmony_ci			  "Couldn't submit rx[%p], ret = %d\n", agg, ret);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		napi_schedule(&tp->napi);
278862306a36Sopenharmony_ci	}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	return ret;
279162306a36Sopenharmony_ci}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_cistatic void rtl_drop_queued_tx(struct r8152 *tp)
279462306a36Sopenharmony_ci{
279562306a36Sopenharmony_ci	struct net_device_stats *stats = &tp->netdev->stats;
279662306a36Sopenharmony_ci	struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
279762306a36Sopenharmony_ci	struct sk_buff *skb;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	if (skb_queue_empty(tx_queue))
280062306a36Sopenharmony_ci		return;
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	__skb_queue_head_init(&skb_head);
280362306a36Sopenharmony_ci	spin_lock_bh(&tx_queue->lock);
280462306a36Sopenharmony_ci	skb_queue_splice_init(tx_queue, &skb_head);
280562306a36Sopenharmony_ci	spin_unlock_bh(&tx_queue->lock);
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&skb_head))) {
280862306a36Sopenharmony_ci		dev_kfree_skb(skb);
280962306a36Sopenharmony_ci		stats->tx_dropped++;
281062306a36Sopenharmony_ci	}
281162306a36Sopenharmony_ci}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_cistatic void rtl8152_tx_timeout(struct net_device *netdev, unsigned int txqueue)
281462306a36Sopenharmony_ci{
281562306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	netif_warn(tp, tx_err, netdev, "Tx timeout\n");
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	usb_queue_reset_device(tp->intf);
282062306a36Sopenharmony_ci}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_cistatic void rtl8152_set_rx_mode(struct net_device *netdev)
282362306a36Sopenharmony_ci{
282462306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
282762306a36Sopenharmony_ci		set_bit(RTL8152_SET_RX_MODE, &tp->flags);
282862306a36Sopenharmony_ci		schedule_delayed_work(&tp->schedule, 0);
282962306a36Sopenharmony_ci	}
283062306a36Sopenharmony_ci}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_cistatic void _rtl8152_set_rx_mode(struct net_device *netdev)
283362306a36Sopenharmony_ci{
283462306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
283562306a36Sopenharmony_ci	u32 mc_filter[2];	/* Multicast hash filter */
283662306a36Sopenharmony_ci	__le32 tmp[2];
283762306a36Sopenharmony_ci	u32 ocp_data;
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	netif_stop_queue(netdev);
284062306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
284162306a36Sopenharmony_ci	ocp_data &= ~RCR_ACPT_ALL;
284262306a36Sopenharmony_ci	ocp_data |= RCR_AB | RCR_APM;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
284562306a36Sopenharmony_ci		/* Unconditionally log net taps. */
284662306a36Sopenharmony_ci		netif_notice(tp, link, netdev, "Promiscuous mode enabled\n");
284762306a36Sopenharmony_ci		ocp_data |= RCR_AM | RCR_AAP;
284862306a36Sopenharmony_ci		mc_filter[1] = 0xffffffff;
284962306a36Sopenharmony_ci		mc_filter[0] = 0xffffffff;
285062306a36Sopenharmony_ci	} else if ((netdev->flags & IFF_MULTICAST &&
285162306a36Sopenharmony_ci				netdev_mc_count(netdev) > multicast_filter_limit) ||
285262306a36Sopenharmony_ci			   (netdev->flags & IFF_ALLMULTI)) {
285362306a36Sopenharmony_ci		/* Too many to filter perfectly -- accept all multicasts. */
285462306a36Sopenharmony_ci		ocp_data |= RCR_AM;
285562306a36Sopenharmony_ci		mc_filter[1] = 0xffffffff;
285662306a36Sopenharmony_ci		mc_filter[0] = 0xffffffff;
285762306a36Sopenharmony_ci	} else {
285862306a36Sopenharmony_ci		mc_filter[1] = 0;
285962306a36Sopenharmony_ci		mc_filter[0] = 0;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci		if (netdev->flags & IFF_MULTICAST) {
286262306a36Sopenharmony_ci			struct netdev_hw_addr *ha;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci			netdev_for_each_mc_addr(ha, netdev) {
286562306a36Sopenharmony_ci				int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci				mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
286862306a36Sopenharmony_ci				ocp_data |= RCR_AM;
286962306a36Sopenharmony_ci			}
287062306a36Sopenharmony_ci		}
287162306a36Sopenharmony_ci	}
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
287462306a36Sopenharmony_ci	tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
287762306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
287862306a36Sopenharmony_ci	netif_wake_queue(netdev);
287962306a36Sopenharmony_ci}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_cistatic netdev_features_t
288262306a36Sopenharmony_cirtl8152_features_check(struct sk_buff *skb, struct net_device *dev,
288362306a36Sopenharmony_ci		       netdev_features_t features)
288462306a36Sopenharmony_ci{
288562306a36Sopenharmony_ci	u32 mss = skb_shinfo(skb)->gso_size;
288662306a36Sopenharmony_ci	int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) &&
288962306a36Sopenharmony_ci	    skb_transport_offset(skb) > max_offset)
289062306a36Sopenharmony_ci		features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
289162306a36Sopenharmony_ci	else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz)
289262306a36Sopenharmony_ci		features &= ~NETIF_F_GSO_MASK;
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci	return features;
289562306a36Sopenharmony_ci}
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_cistatic netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
289862306a36Sopenharmony_ci				      struct net_device *netdev)
289962306a36Sopenharmony_ci{
290062306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	skb_tx_timestamp(skb);
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	skb_queue_tail(&tp->tx_queue, skb);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	if (!list_empty(&tp->tx_free)) {
290762306a36Sopenharmony_ci		if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
290862306a36Sopenharmony_ci			set_bit(SCHEDULE_TASKLET, &tp->flags);
290962306a36Sopenharmony_ci			schedule_delayed_work(&tp->schedule, 0);
291062306a36Sopenharmony_ci		} else {
291162306a36Sopenharmony_ci			usb_mark_last_busy(tp->udev);
291262306a36Sopenharmony_ci			tasklet_schedule(&tp->tx_tl);
291362306a36Sopenharmony_ci		}
291462306a36Sopenharmony_ci	} else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) {
291562306a36Sopenharmony_ci		netif_stop_queue(netdev);
291662306a36Sopenharmony_ci	}
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci	return NETDEV_TX_OK;
291962306a36Sopenharmony_ci}
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_cistatic void r8152b_reset_packet_filter(struct r8152 *tp)
292262306a36Sopenharmony_ci{
292362306a36Sopenharmony_ci	u32 ocp_data;
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
292662306a36Sopenharmony_ci	ocp_data &= ~FMC_FCR_MCU_EN;
292762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
292862306a36Sopenharmony_ci	ocp_data |= FMC_FCR_MCU_EN;
292962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
293062306a36Sopenharmony_ci}
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_cistatic void rtl8152_nic_reset(struct r8152 *tp)
293362306a36Sopenharmony_ci{
293462306a36Sopenharmony_ci	u32 ocp_data;
293562306a36Sopenharmony_ci	int i;
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci	switch (tp->version) {
293862306a36Sopenharmony_ci	case RTL_TEST_01:
293962306a36Sopenharmony_ci	case RTL_VER_10:
294062306a36Sopenharmony_ci	case RTL_VER_11:
294162306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
294262306a36Sopenharmony_ci		ocp_data &= ~CR_TE;
294362306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
294662306a36Sopenharmony_ci		ocp_data &= ~BMU_RESET_EP_IN;
294762306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
295062306a36Sopenharmony_ci		ocp_data |= CDC_ECM_EN;
295162306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
295462306a36Sopenharmony_ci		ocp_data &= ~CR_RE;
295562306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
295862306a36Sopenharmony_ci		ocp_data |= BMU_RESET_EP_IN;
295962306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
296262306a36Sopenharmony_ci		ocp_data &= ~CDC_ECM_EN;
296362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
296462306a36Sopenharmony_ci		break;
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	default:
296762306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci		for (i = 0; i < 1000; i++) {
297062306a36Sopenharmony_ci			if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
297162306a36Sopenharmony_ci				break;
297262306a36Sopenharmony_ci			if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
297362306a36Sopenharmony_ci				break;
297462306a36Sopenharmony_ci			usleep_range(100, 400);
297562306a36Sopenharmony_ci		}
297662306a36Sopenharmony_ci		break;
297762306a36Sopenharmony_ci	}
297862306a36Sopenharmony_ci}
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_cistatic void set_tx_qlen(struct r8152 *tp)
298162306a36Sopenharmony_ci{
298262306a36Sopenharmony_ci	tp->tx_qlen = agg_buf_sz / (mtu_to_size(tp->netdev->mtu) + sizeof(struct tx_desc));
298362306a36Sopenharmony_ci}
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_cistatic inline u16 rtl8152_get_speed(struct r8152 *tp)
298662306a36Sopenharmony_ci{
298762306a36Sopenharmony_ci	return ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
298862306a36Sopenharmony_ci}
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_cistatic void rtl_eee_plus_en(struct r8152 *tp, bool enable)
299162306a36Sopenharmony_ci{
299262306a36Sopenharmony_ci	u32 ocp_data;
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
299562306a36Sopenharmony_ci	if (enable)
299662306a36Sopenharmony_ci		ocp_data |= EEEP_CR_EEEP_TX;
299762306a36Sopenharmony_ci	else
299862306a36Sopenharmony_ci		ocp_data &= ~EEEP_CR_EEEP_TX;
299962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
300062306a36Sopenharmony_ci}
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_cistatic void rtl_set_eee_plus(struct r8152 *tp)
300362306a36Sopenharmony_ci{
300462306a36Sopenharmony_ci	if (rtl8152_get_speed(tp) & _10bps)
300562306a36Sopenharmony_ci		rtl_eee_plus_en(tp, true);
300662306a36Sopenharmony_ci	else
300762306a36Sopenharmony_ci		rtl_eee_plus_en(tp, false);
300862306a36Sopenharmony_ci}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_cistatic void rxdy_gated_en(struct r8152 *tp, bool enable)
301162306a36Sopenharmony_ci{
301262306a36Sopenharmony_ci	u32 ocp_data;
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
301562306a36Sopenharmony_ci	if (enable)
301662306a36Sopenharmony_ci		ocp_data |= RXDY_GATED_EN;
301762306a36Sopenharmony_ci	else
301862306a36Sopenharmony_ci		ocp_data &= ~RXDY_GATED_EN;
301962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
302062306a36Sopenharmony_ci}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_cistatic int rtl_start_rx(struct r8152 *tp)
302362306a36Sopenharmony_ci{
302462306a36Sopenharmony_ci	struct rx_agg *agg, *agg_next;
302562306a36Sopenharmony_ci	struct list_head tmp_list;
302662306a36Sopenharmony_ci	unsigned long flags;
302762306a36Sopenharmony_ci	int ret = 0, i = 0;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	INIT_LIST_HEAD(&tmp_list);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	INIT_LIST_HEAD(&tp->rx_done);
303462306a36Sopenharmony_ci	INIT_LIST_HEAD(&tp->rx_used);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	list_splice_init(&tp->rx_info, &tmp_list);
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) {
304162306a36Sopenharmony_ci		INIT_LIST_HEAD(&agg->list);
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci		/* Only RTL8152_MAX_RX rx_agg need to be submitted. */
304462306a36Sopenharmony_ci		if (++i > RTL8152_MAX_RX) {
304562306a36Sopenharmony_ci			spin_lock_irqsave(&tp->rx_lock, flags);
304662306a36Sopenharmony_ci			list_add_tail(&agg->list, &tp->rx_used);
304762306a36Sopenharmony_ci			spin_unlock_irqrestore(&tp->rx_lock, flags);
304862306a36Sopenharmony_ci		} else if (unlikely(ret < 0)) {
304962306a36Sopenharmony_ci			spin_lock_irqsave(&tp->rx_lock, flags);
305062306a36Sopenharmony_ci			list_add_tail(&agg->list, &tp->rx_done);
305162306a36Sopenharmony_ci			spin_unlock_irqrestore(&tp->rx_lock, flags);
305262306a36Sopenharmony_ci		} else {
305362306a36Sopenharmony_ci			ret = r8152_submit_rx(tp, agg, GFP_KERNEL);
305462306a36Sopenharmony_ci		}
305562306a36Sopenharmony_ci	}
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
305862306a36Sopenharmony_ci	WARN_ON(!list_empty(&tp->rx_info));
305962306a36Sopenharmony_ci	list_splice(&tmp_list, &tp->rx_info);
306062306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	return ret;
306362306a36Sopenharmony_ci}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_cistatic int rtl_stop_rx(struct r8152 *tp)
306662306a36Sopenharmony_ci{
306762306a36Sopenharmony_ci	struct rx_agg *agg, *agg_next;
306862306a36Sopenharmony_ci	struct list_head tmp_list;
306962306a36Sopenharmony_ci	unsigned long flags;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	INIT_LIST_HEAD(&tmp_list);
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	/* The usb_kill_urb() couldn't be used in atomic.
307462306a36Sopenharmony_ci	 * Therefore, move the list of rx_info to a tmp one.
307562306a36Sopenharmony_ci	 * Then, list_for_each_entry_safe could be used without
307662306a36Sopenharmony_ci	 * spin lock.
307762306a36Sopenharmony_ci	 */
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
308062306a36Sopenharmony_ci	list_splice_init(&tp->rx_info, &tmp_list);
308162306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) {
308462306a36Sopenharmony_ci		/* At least RTL8152_MAX_RX rx_agg have the page_count being
308562306a36Sopenharmony_ci		 * equal to 1, so the other ones could be freed safely.
308662306a36Sopenharmony_ci		 */
308762306a36Sopenharmony_ci		if (page_count(agg->page) > 1)
308862306a36Sopenharmony_ci			free_rx_agg(tp, agg);
308962306a36Sopenharmony_ci		else
309062306a36Sopenharmony_ci			usb_kill_urb(agg->urb);
309162306a36Sopenharmony_ci	}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	/* Move back the list of temp to the rx_info */
309462306a36Sopenharmony_ci	spin_lock_irqsave(&tp->rx_lock, flags);
309562306a36Sopenharmony_ci	WARN_ON(!list_empty(&tp->rx_info));
309662306a36Sopenharmony_ci	list_splice(&tmp_list, &tp->rx_info);
309762306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->rx_lock, flags);
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci	while (!skb_queue_empty(&tp->rx_queue))
310062306a36Sopenharmony_ci		dev_kfree_skb(__skb_dequeue(&tp->rx_queue));
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	return 0;
310362306a36Sopenharmony_ci}
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_cistatic void rtl_set_ifg(struct r8152 *tp, u16 speed)
310662306a36Sopenharmony_ci{
310762306a36Sopenharmony_ci	u32 ocp_data;
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1);
311062306a36Sopenharmony_ci	ocp_data &= ~IFG_MASK;
311162306a36Sopenharmony_ci	if ((speed & (_10bps | _100bps)) && !(speed & FULL_DUP)) {
311262306a36Sopenharmony_ci		ocp_data |= IFG_144NS;
311362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR1, ocp_data);
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
311662306a36Sopenharmony_ci		ocp_data &= ~TX10MIDLE_EN;
311762306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
311862306a36Sopenharmony_ci	} else {
311962306a36Sopenharmony_ci		ocp_data |= IFG_96NS;
312062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR1, ocp_data);
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
312362306a36Sopenharmony_ci		ocp_data |= TX10MIDLE_EN;
312462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
312562306a36Sopenharmony_ci	}
312662306a36Sopenharmony_ci}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_cistatic inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp)
312962306a36Sopenharmony_ci{
313062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
313162306a36Sopenharmony_ci		       OWN_UPDATE | OWN_CLEAR);
313262306a36Sopenharmony_ci}
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_cistatic int rtl_enable(struct r8152 *tp)
313562306a36Sopenharmony_ci{
313662306a36Sopenharmony_ci	u32 ocp_data;
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	r8152b_reset_packet_filter(tp);
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
314162306a36Sopenharmony_ci	ocp_data |= CR_RE | CR_TE;
314262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	switch (tp->version) {
314562306a36Sopenharmony_ci	case RTL_VER_01:
314662306a36Sopenharmony_ci	case RTL_VER_02:
314762306a36Sopenharmony_ci	case RTL_VER_03:
314862306a36Sopenharmony_ci	case RTL_VER_04:
314962306a36Sopenharmony_ci	case RTL_VER_05:
315062306a36Sopenharmony_ci	case RTL_VER_06:
315162306a36Sopenharmony_ci	case RTL_VER_07:
315262306a36Sopenharmony_ci		break;
315362306a36Sopenharmony_ci	default:
315462306a36Sopenharmony_ci		r8153b_rx_agg_chg_indicate(tp);
315562306a36Sopenharmony_ci		break;
315662306a36Sopenharmony_ci	}
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	rxdy_gated_en(tp, false);
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	return 0;
316162306a36Sopenharmony_ci}
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_cistatic int rtl8152_enable(struct r8152 *tp)
316462306a36Sopenharmony_ci{
316562306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
316662306a36Sopenharmony_ci		return -ENODEV;
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	set_tx_qlen(tp);
316962306a36Sopenharmony_ci	rtl_set_eee_plus(tp);
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	return rtl_enable(tp);
317262306a36Sopenharmony_ci}
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_cistatic void r8153_set_rx_early_timeout(struct r8152 *tp)
317562306a36Sopenharmony_ci{
317662306a36Sopenharmony_ci	u32 ocp_data = tp->coalesce / 8;
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	switch (tp->version) {
317962306a36Sopenharmony_ci	case RTL_VER_03:
318062306a36Sopenharmony_ci	case RTL_VER_04:
318162306a36Sopenharmony_ci	case RTL_VER_05:
318262306a36Sopenharmony_ci	case RTL_VER_06:
318362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
318462306a36Sopenharmony_ci			       ocp_data);
318562306a36Sopenharmony_ci		break;
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	case RTL_VER_08:
318862306a36Sopenharmony_ci	case RTL_VER_09:
318962306a36Sopenharmony_ci	case RTL_VER_14:
319062306a36Sopenharmony_ci		/* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout
319162306a36Sopenharmony_ci		 * primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 128ns.
319262306a36Sopenharmony_ci		 */
319362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
319462306a36Sopenharmony_ci			       128 / 8);
319562306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
319662306a36Sopenharmony_ci			       ocp_data);
319762306a36Sopenharmony_ci		break;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	case RTL_VER_10:
320062306a36Sopenharmony_ci	case RTL_VER_11:
320162306a36Sopenharmony_ci	case RTL_VER_12:
320262306a36Sopenharmony_ci	case RTL_VER_13:
320362306a36Sopenharmony_ci	case RTL_VER_15:
320462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
320562306a36Sopenharmony_ci			       640 / 8);
320662306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
320762306a36Sopenharmony_ci			       ocp_data);
320862306a36Sopenharmony_ci		break;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	default:
321162306a36Sopenharmony_ci		break;
321262306a36Sopenharmony_ci	}
321362306a36Sopenharmony_ci}
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_cistatic void r8153_set_rx_early_size(struct r8152 *tp)
321662306a36Sopenharmony_ci{
321762306a36Sopenharmony_ci	u32 ocp_data = tp->rx_buf_sz - rx_reserved_size(tp->netdev->mtu);
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	switch (tp->version) {
322062306a36Sopenharmony_ci	case RTL_VER_03:
322162306a36Sopenharmony_ci	case RTL_VER_04:
322262306a36Sopenharmony_ci	case RTL_VER_05:
322362306a36Sopenharmony_ci	case RTL_VER_06:
322462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
322562306a36Sopenharmony_ci			       ocp_data / 4);
322662306a36Sopenharmony_ci		break;
322762306a36Sopenharmony_ci	case RTL_VER_08:
322862306a36Sopenharmony_ci	case RTL_VER_09:
322962306a36Sopenharmony_ci	case RTL_VER_14:
323062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
323162306a36Sopenharmony_ci			       ocp_data / 8);
323262306a36Sopenharmony_ci		break;
323362306a36Sopenharmony_ci	case RTL_TEST_01:
323462306a36Sopenharmony_ci	case RTL_VER_10:
323562306a36Sopenharmony_ci	case RTL_VER_11:
323662306a36Sopenharmony_ci	case RTL_VER_12:
323762306a36Sopenharmony_ci	case RTL_VER_13:
323862306a36Sopenharmony_ci	case RTL_VER_15:
323962306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
324062306a36Sopenharmony_ci			       ocp_data / 8);
324162306a36Sopenharmony_ci		break;
324262306a36Sopenharmony_ci	default:
324362306a36Sopenharmony_ci		WARN_ON_ONCE(1);
324462306a36Sopenharmony_ci		break;
324562306a36Sopenharmony_ci	}
324662306a36Sopenharmony_ci}
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_cistatic int rtl8153_enable(struct r8152 *tp)
324962306a36Sopenharmony_ci{
325062306a36Sopenharmony_ci	u32 ocp_data;
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
325362306a36Sopenharmony_ci		return -ENODEV;
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	set_tx_qlen(tp);
325662306a36Sopenharmony_ci	rtl_set_eee_plus(tp);
325762306a36Sopenharmony_ci	r8153_set_rx_early_timeout(tp);
325862306a36Sopenharmony_ci	r8153_set_rx_early_size(tp);
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	rtl_set_ifg(tp, rtl8152_get_speed(tp));
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	switch (tp->version) {
326362306a36Sopenharmony_ci	case RTL_VER_09:
326462306a36Sopenharmony_ci	case RTL_VER_14:
326562306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
326662306a36Sopenharmony_ci		ocp_data &= ~FC_PATCH_TASK;
326762306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
326862306a36Sopenharmony_ci		usleep_range(1000, 2000);
326962306a36Sopenharmony_ci		ocp_data |= FC_PATCH_TASK;
327062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
327162306a36Sopenharmony_ci		break;
327262306a36Sopenharmony_ci	default:
327362306a36Sopenharmony_ci		break;
327462306a36Sopenharmony_ci	}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	return rtl_enable(tp);
327762306a36Sopenharmony_ci}
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_cistatic void rtl_disable(struct r8152 *tp)
328062306a36Sopenharmony_ci{
328162306a36Sopenharmony_ci	u32 ocp_data;
328262306a36Sopenharmony_ci	int i;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
328562306a36Sopenharmony_ci		rtl_drop_queued_tx(tp);
328662306a36Sopenharmony_ci		return;
328762306a36Sopenharmony_ci	}
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
329062306a36Sopenharmony_ci	ocp_data &= ~RCR_ACPT_ALL;
329162306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	rtl_drop_queued_tx(tp);
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	for (i = 0; i < RTL8152_MAX_TX; i++)
329662306a36Sopenharmony_ci		usb_kill_urb(tp->tx_info[i].urb);
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	rxdy_gated_en(tp, true);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	for (i = 0; i < 1000; i++) {
330162306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
330262306a36Sopenharmony_ci			break;
330362306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
330462306a36Sopenharmony_ci		if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
330562306a36Sopenharmony_ci			break;
330662306a36Sopenharmony_ci		usleep_range(1000, 2000);
330762306a36Sopenharmony_ci	}
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	for (i = 0; i < 1000; i++) {
331062306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
331162306a36Sopenharmony_ci			break;
331262306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
331362306a36Sopenharmony_ci			break;
331462306a36Sopenharmony_ci		usleep_range(1000, 2000);
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci	rtl_stop_rx(tp);
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
332062306a36Sopenharmony_ci}
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_cistatic void r8152_power_cut_en(struct r8152 *tp, bool enable)
332362306a36Sopenharmony_ci{
332462306a36Sopenharmony_ci	u32 ocp_data;
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
332762306a36Sopenharmony_ci	if (enable)
332862306a36Sopenharmony_ci		ocp_data |= POWER_CUT;
332962306a36Sopenharmony_ci	else
333062306a36Sopenharmony_ci		ocp_data &= ~POWER_CUT;
333162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
333462306a36Sopenharmony_ci	ocp_data &= ~RESUME_INDICATE;
333562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
333662306a36Sopenharmony_ci}
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_cistatic void rtl_rx_vlan_en(struct r8152 *tp, bool enable)
333962306a36Sopenharmony_ci{
334062306a36Sopenharmony_ci	u32 ocp_data;
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	switch (tp->version) {
334362306a36Sopenharmony_ci	case RTL_VER_01:
334462306a36Sopenharmony_ci	case RTL_VER_02:
334562306a36Sopenharmony_ci	case RTL_VER_03:
334662306a36Sopenharmony_ci	case RTL_VER_04:
334762306a36Sopenharmony_ci	case RTL_VER_05:
334862306a36Sopenharmony_ci	case RTL_VER_06:
334962306a36Sopenharmony_ci	case RTL_VER_07:
335062306a36Sopenharmony_ci	case RTL_VER_08:
335162306a36Sopenharmony_ci	case RTL_VER_09:
335262306a36Sopenharmony_ci	case RTL_VER_14:
335362306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
335462306a36Sopenharmony_ci		if (enable)
335562306a36Sopenharmony_ci			ocp_data |= CPCR_RX_VLAN;
335662306a36Sopenharmony_ci		else
335762306a36Sopenharmony_ci			ocp_data &= ~CPCR_RX_VLAN;
335862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
335962306a36Sopenharmony_ci		break;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	case RTL_TEST_01:
336262306a36Sopenharmony_ci	case RTL_VER_10:
336362306a36Sopenharmony_ci	case RTL_VER_11:
336462306a36Sopenharmony_ci	case RTL_VER_12:
336562306a36Sopenharmony_ci	case RTL_VER_13:
336662306a36Sopenharmony_ci	case RTL_VER_15:
336762306a36Sopenharmony_ci	default:
336862306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RCR1);
336962306a36Sopenharmony_ci		if (enable)
337062306a36Sopenharmony_ci			ocp_data |= OUTER_VLAN | INNER_VLAN;
337162306a36Sopenharmony_ci		else
337262306a36Sopenharmony_ci			ocp_data &= ~(OUTER_VLAN | INNER_VLAN);
337362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RCR1, ocp_data);
337462306a36Sopenharmony_ci		break;
337562306a36Sopenharmony_ci	}
337662306a36Sopenharmony_ci}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_cistatic int rtl8152_set_features(struct net_device *dev,
337962306a36Sopenharmony_ci				netdev_features_t features)
338062306a36Sopenharmony_ci{
338162306a36Sopenharmony_ci	netdev_features_t changed = features ^ dev->features;
338262306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
338362306a36Sopenharmony_ci	int ret;
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
338662306a36Sopenharmony_ci	if (ret < 0)
338762306a36Sopenharmony_ci		goto out;
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	mutex_lock(&tp->control);
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
339262306a36Sopenharmony_ci		if (features & NETIF_F_HW_VLAN_CTAG_RX)
339362306a36Sopenharmony_ci			rtl_rx_vlan_en(tp, true);
339462306a36Sopenharmony_ci		else
339562306a36Sopenharmony_ci			rtl_rx_vlan_en(tp, false);
339662306a36Sopenharmony_ci	}
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	mutex_unlock(&tp->control);
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ciout:
340362306a36Sopenharmony_ci	return ret;
340462306a36Sopenharmony_ci}
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_cistatic u32 __rtl_get_wol(struct r8152 *tp)
340962306a36Sopenharmony_ci{
341062306a36Sopenharmony_ci	u32 ocp_data;
341162306a36Sopenharmony_ci	u32 wolopts = 0;
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
341462306a36Sopenharmony_ci	if (ocp_data & LINK_ON_WAKE_EN)
341562306a36Sopenharmony_ci		wolopts |= WAKE_PHY;
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
341862306a36Sopenharmony_ci	if (ocp_data & UWF_EN)
341962306a36Sopenharmony_ci		wolopts |= WAKE_UCAST;
342062306a36Sopenharmony_ci	if (ocp_data & BWF_EN)
342162306a36Sopenharmony_ci		wolopts |= WAKE_BCAST;
342262306a36Sopenharmony_ci	if (ocp_data & MWF_EN)
342362306a36Sopenharmony_ci		wolopts |= WAKE_MCAST;
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
342662306a36Sopenharmony_ci	if (ocp_data & MAGIC_EN)
342762306a36Sopenharmony_ci		wolopts |= WAKE_MAGIC;
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	return wolopts;
343062306a36Sopenharmony_ci}
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_cistatic void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
343362306a36Sopenharmony_ci{
343462306a36Sopenharmony_ci	u32 ocp_data;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
343962306a36Sopenharmony_ci	ocp_data &= ~LINK_ON_WAKE_EN;
344062306a36Sopenharmony_ci	if (wolopts & WAKE_PHY)
344162306a36Sopenharmony_ci		ocp_data |= LINK_ON_WAKE_EN;
344262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
344562306a36Sopenharmony_ci	ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN);
344662306a36Sopenharmony_ci	if (wolopts & WAKE_UCAST)
344762306a36Sopenharmony_ci		ocp_data |= UWF_EN;
344862306a36Sopenharmony_ci	if (wolopts & WAKE_BCAST)
344962306a36Sopenharmony_ci		ocp_data |= BWF_EN;
345062306a36Sopenharmony_ci	if (wolopts & WAKE_MCAST)
345162306a36Sopenharmony_ci		ocp_data |= MWF_EN;
345262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
345762306a36Sopenharmony_ci	ocp_data &= ~MAGIC_EN;
345862306a36Sopenharmony_ci	if (wolopts & WAKE_MAGIC)
345962306a36Sopenharmony_ci		ocp_data |= MAGIC_EN;
346062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	if (wolopts & WAKE_ANY)
346362306a36Sopenharmony_ci		device_set_wakeup_enable(&tp->udev->dev, true);
346462306a36Sopenharmony_ci	else
346562306a36Sopenharmony_ci		device_set_wakeup_enable(&tp->udev->dev, false);
346662306a36Sopenharmony_ci}
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_cistatic void r8153_mac_clk_speed_down(struct r8152 *tp, bool enable)
346962306a36Sopenharmony_ci{
347062306a36Sopenharmony_ci	u32 ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	/* MAC clock speed down */
347362306a36Sopenharmony_ci	if (enable)
347462306a36Sopenharmony_ci		ocp_data |= MAC_CLK_SPDWN_EN;
347562306a36Sopenharmony_ci	else
347662306a36Sopenharmony_ci		ocp_data &= ~MAC_CLK_SPDWN_EN;
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
347962306a36Sopenharmony_ci}
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_cistatic void r8156_mac_clk_spd(struct r8152 *tp, bool enable)
348262306a36Sopenharmony_ci{
348362306a36Sopenharmony_ci	u32 ocp_data;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	/* MAC clock speed down */
348662306a36Sopenharmony_ci	if (enable) {
348762306a36Sopenharmony_ci		/* aldps_spdwn_ratio, tp10_spdwn_ratio */
348862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL,
348962306a36Sopenharmony_ci			       0x0403);
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
349262306a36Sopenharmony_ci		ocp_data &= ~EEE_SPDWN_RATIO_MASK;
349362306a36Sopenharmony_ci		ocp_data |= MAC_CLK_SPDWN_EN | 0x03; /* eee_spdwn_ratio */
349462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
349562306a36Sopenharmony_ci	} else {
349662306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
349762306a36Sopenharmony_ci		ocp_data &= ~MAC_CLK_SPDWN_EN;
349862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
349962306a36Sopenharmony_ci	}
350062306a36Sopenharmony_ci}
350162306a36Sopenharmony_ci
350262306a36Sopenharmony_cistatic void r8153_u1u2en(struct r8152 *tp, bool enable)
350362306a36Sopenharmony_ci{
350462306a36Sopenharmony_ci	u8 u1u2[8];
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	if (enable)
350762306a36Sopenharmony_ci		memset(u1u2, 0xff, sizeof(u1u2));
350862306a36Sopenharmony_ci	else
350962306a36Sopenharmony_ci		memset(u1u2, 0x00, sizeof(u1u2));
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
351262306a36Sopenharmony_ci}
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_cistatic void r8153b_u1u2en(struct r8152 *tp, bool enable)
351562306a36Sopenharmony_ci{
351662306a36Sopenharmony_ci	u32 ocp_data;
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG);
351962306a36Sopenharmony_ci	if (enable)
352062306a36Sopenharmony_ci		ocp_data |= LPM_U1U2_EN;
352162306a36Sopenharmony_ci	else
352262306a36Sopenharmony_ci		ocp_data &= ~LPM_U1U2_EN;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG, ocp_data);
352562306a36Sopenharmony_ci}
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_cistatic void r8153_u2p3en(struct r8152 *tp, bool enable)
352862306a36Sopenharmony_ci{
352962306a36Sopenharmony_ci	u32 ocp_data;
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
353262306a36Sopenharmony_ci	if (enable)
353362306a36Sopenharmony_ci		ocp_data |= U2P3_ENABLE;
353462306a36Sopenharmony_ci	else
353562306a36Sopenharmony_ci		ocp_data &= ~U2P3_ENABLE;
353662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
353762306a36Sopenharmony_ci}
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_cistatic void r8153b_ups_flags(struct r8152 *tp)
354062306a36Sopenharmony_ci{
354162306a36Sopenharmony_ci	u32 ups_flags = 0;
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	if (tp->ups_info.green)
354462306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_GREEN;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	if (tp->ups_info.aldps)
354762306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_ALDPS;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	if (tp->ups_info.eee)
355062306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_EEE;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	if (tp->ups_info.flow_control)
355362306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_FLOW_CTR;
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	if (tp->ups_info.eee_ckdiv)
355662306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_EEE_CKDIV;
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci	if (tp->ups_info.eee_cmod_lv)
355962306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EEE_CMOD_LV_EN;
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	if (tp->ups_info.r_tune)
356262306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_R_TUNE;
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	if (tp->ups_info._10m_ckdiv)
356562306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_10M_CKDIV;
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	if (tp->ups_info.eee_plloff_100)
356862306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EEE_PLLOFF_100;
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	if (tp->ups_info.eee_plloff_giga)
357162306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EEE_PLLOFF_GIGA;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	if (tp->ups_info._250m_ckdiv)
357462306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_250M_CKDIV;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	if (tp->ups_info.ctap_short_off)
357762306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_CTAP_SHORT_DIS;
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	switch (tp->ups_info.speed_duplex) {
358062306a36Sopenharmony_ci	case NWAY_10M_HALF:
358162306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(1);
358262306a36Sopenharmony_ci		break;
358362306a36Sopenharmony_ci	case NWAY_10M_FULL:
358462306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(2);
358562306a36Sopenharmony_ci		break;
358662306a36Sopenharmony_ci	case NWAY_100M_HALF:
358762306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(3);
358862306a36Sopenharmony_ci		break;
358962306a36Sopenharmony_ci	case NWAY_100M_FULL:
359062306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(4);
359162306a36Sopenharmony_ci		break;
359262306a36Sopenharmony_ci	case NWAY_1000M_FULL:
359362306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(5);
359462306a36Sopenharmony_ci		break;
359562306a36Sopenharmony_ci	case FORCE_10M_HALF:
359662306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(6);
359762306a36Sopenharmony_ci		break;
359862306a36Sopenharmony_ci	case FORCE_10M_FULL:
359962306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(7);
360062306a36Sopenharmony_ci		break;
360162306a36Sopenharmony_ci	case FORCE_100M_HALF:
360262306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(8);
360362306a36Sopenharmony_ci		break;
360462306a36Sopenharmony_ci	case FORCE_100M_FULL:
360562306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(9);
360662306a36Sopenharmony_ci		break;
360762306a36Sopenharmony_ci	default:
360862306a36Sopenharmony_ci		break;
360962306a36Sopenharmony_ci	}
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ups_flags);
361262306a36Sopenharmony_ci}
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_cistatic void r8156_ups_flags(struct r8152 *tp)
361562306a36Sopenharmony_ci{
361662306a36Sopenharmony_ci	u32 ups_flags = 0;
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ci	if (tp->ups_info.green)
361962306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_GREEN;
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	if (tp->ups_info.aldps)
362262306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_ALDPS;
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	if (tp->ups_info.eee)
362562306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_EEE;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	if (tp->ups_info.flow_control)
362862306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_FLOW_CTR;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	if (tp->ups_info.eee_ckdiv)
363162306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_EEE_CKDIV;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	if (tp->ups_info._10m_ckdiv)
363462306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EN_10M_CKDIV;
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci	if (tp->ups_info.eee_plloff_100)
363762306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EEE_PLLOFF_100;
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	if (tp->ups_info.eee_plloff_giga)
364062306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_EEE_PLLOFF_GIGA;
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	if (tp->ups_info._250m_ckdiv)
364362306a36Sopenharmony_ci		ups_flags |= UPS_FLAGS_250M_CKDIV;
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci	switch (tp->ups_info.speed_duplex) {
364662306a36Sopenharmony_ci	case FORCE_10M_HALF:
364762306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(0);
364862306a36Sopenharmony_ci		break;
364962306a36Sopenharmony_ci	case FORCE_10M_FULL:
365062306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(1);
365162306a36Sopenharmony_ci		break;
365262306a36Sopenharmony_ci	case FORCE_100M_HALF:
365362306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(2);
365462306a36Sopenharmony_ci		break;
365562306a36Sopenharmony_ci	case FORCE_100M_FULL:
365662306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(3);
365762306a36Sopenharmony_ci		break;
365862306a36Sopenharmony_ci	case NWAY_10M_HALF:
365962306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(4);
366062306a36Sopenharmony_ci		break;
366162306a36Sopenharmony_ci	case NWAY_10M_FULL:
366262306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(5);
366362306a36Sopenharmony_ci		break;
366462306a36Sopenharmony_ci	case NWAY_100M_HALF:
366562306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(6);
366662306a36Sopenharmony_ci		break;
366762306a36Sopenharmony_ci	case NWAY_100M_FULL:
366862306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(7);
366962306a36Sopenharmony_ci		break;
367062306a36Sopenharmony_ci	case NWAY_1000M_FULL:
367162306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(8);
367262306a36Sopenharmony_ci		break;
367362306a36Sopenharmony_ci	case NWAY_2500M_FULL:
367462306a36Sopenharmony_ci		ups_flags |= ups_flags_speed(9);
367562306a36Sopenharmony_ci		break;
367662306a36Sopenharmony_ci	default:
367762306a36Sopenharmony_ci		break;
367862306a36Sopenharmony_ci	}
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci	switch (tp->ups_info.lite_mode) {
368162306a36Sopenharmony_ci	case 1:
368262306a36Sopenharmony_ci		ups_flags |= 0 << 5;
368362306a36Sopenharmony_ci		break;
368462306a36Sopenharmony_ci	case 2:
368562306a36Sopenharmony_ci		ups_flags |= 2 << 5;
368662306a36Sopenharmony_ci		break;
368762306a36Sopenharmony_ci	case 0:
368862306a36Sopenharmony_ci	default:
368962306a36Sopenharmony_ci		ups_flags |= 1 << 5;
369062306a36Sopenharmony_ci		break;
369162306a36Sopenharmony_ci	}
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ups_flags);
369462306a36Sopenharmony_ci}
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_cistatic void rtl_green_en(struct r8152 *tp, bool enable)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	u16 data;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	data = sram_read(tp, SRAM_GREEN_CFG);
370162306a36Sopenharmony_ci	if (enable)
370262306a36Sopenharmony_ci		data |= GREEN_ETH_EN;
370362306a36Sopenharmony_ci	else
370462306a36Sopenharmony_ci		data &= ~GREEN_ETH_EN;
370562306a36Sopenharmony_ci	sram_write(tp, SRAM_GREEN_CFG, data);
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci	tp->ups_info.green = enable;
370862306a36Sopenharmony_ci}
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_cistatic void r8153b_green_en(struct r8152 *tp, bool enable)
371162306a36Sopenharmony_ci{
371262306a36Sopenharmony_ci	if (enable) {
371362306a36Sopenharmony_ci		sram_write(tp, 0x8045, 0);	/* 10M abiq&ldvbias */
371462306a36Sopenharmony_ci		sram_write(tp, 0x804d, 0x1222);	/* 100M short abiq&ldvbias */
371562306a36Sopenharmony_ci		sram_write(tp, 0x805d, 0x0022);	/* 1000M short abiq&ldvbias */
371662306a36Sopenharmony_ci	} else {
371762306a36Sopenharmony_ci		sram_write(tp, 0x8045, 0x2444);	/* 10M abiq&ldvbias */
371862306a36Sopenharmony_ci		sram_write(tp, 0x804d, 0x2444);	/* 100M short abiq&ldvbias */
371962306a36Sopenharmony_ci		sram_write(tp, 0x805d, 0x2444);	/* 1000M short abiq&ldvbias */
372062306a36Sopenharmony_ci	}
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	rtl_green_en(tp, true);
372362306a36Sopenharmony_ci}
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_cistatic u16 r8153_phy_status(struct r8152 *tp, u16 desired)
372662306a36Sopenharmony_ci{
372762306a36Sopenharmony_ci	u16 data;
372862306a36Sopenharmony_ci	int i;
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
373162306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_PHY_STATUS);
373262306a36Sopenharmony_ci		data &= PHY_STAT_MASK;
373362306a36Sopenharmony_ci		if (desired) {
373462306a36Sopenharmony_ci			if (data == desired)
373562306a36Sopenharmony_ci				break;
373662306a36Sopenharmony_ci		} else if (data == PHY_STAT_LAN_ON || data == PHY_STAT_PWRDN ||
373762306a36Sopenharmony_ci			   data == PHY_STAT_EXT_INIT) {
373862306a36Sopenharmony_ci			break;
373962306a36Sopenharmony_ci		}
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci		msleep(20);
374262306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
374362306a36Sopenharmony_ci			break;
374462306a36Sopenharmony_ci	}
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci	return data;
374762306a36Sopenharmony_ci}
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_cistatic void r8153b_ups_en(struct r8152 *tp, bool enable)
375062306a36Sopenharmony_ci{
375162306a36Sopenharmony_ci	u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT);
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	if (enable) {
375462306a36Sopenharmony_ci		r8153b_ups_flags(tp);
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci		ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN;
375762306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
376062306a36Sopenharmony_ci		ocp_data |= UPS_FORCE_PWR_DOWN;
376162306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
376262306a36Sopenharmony_ci	} else {
376362306a36Sopenharmony_ci		ocp_data &= ~(UPS_EN | USP_PREWAKE);
376462306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
376762306a36Sopenharmony_ci		ocp_data &= ~UPS_FORCE_PWR_DOWN;
376862306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
377162306a36Sopenharmony_ci			int i;
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci			for (i = 0; i < 500; i++) {
377462306a36Sopenharmony_ci				if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
377562306a36Sopenharmony_ci					return;
377662306a36Sopenharmony_ci				if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
377762306a36Sopenharmony_ci				    AUTOLOAD_DONE)
377862306a36Sopenharmony_ci					break;
377962306a36Sopenharmony_ci				msleep(20);
378062306a36Sopenharmony_ci			}
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci			tp->rtl_ops.hw_phy_cfg(tp);
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci			rtl8152_set_speed(tp, tp->autoneg, tp->speed,
378562306a36Sopenharmony_ci					  tp->duplex, tp->advertising);
378662306a36Sopenharmony_ci		}
378762306a36Sopenharmony_ci	}
378862306a36Sopenharmony_ci}
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_cistatic void r8153c_ups_en(struct r8152 *tp, bool enable)
379162306a36Sopenharmony_ci{
379262306a36Sopenharmony_ci	u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT);
379362306a36Sopenharmony_ci
379462306a36Sopenharmony_ci	if (enable) {
379562306a36Sopenharmony_ci		r8153b_ups_flags(tp);
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci		ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN;
379862306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
380162306a36Sopenharmony_ci		ocp_data |= UPS_FORCE_PWR_DOWN;
380262306a36Sopenharmony_ci		ocp_data &= ~BIT(7);
380362306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
380462306a36Sopenharmony_ci	} else {
380562306a36Sopenharmony_ci		ocp_data &= ~(UPS_EN | USP_PREWAKE);
380662306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
380962306a36Sopenharmony_ci		ocp_data &= ~UPS_FORCE_PWR_DOWN;
381062306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
381362306a36Sopenharmony_ci			int i;
381462306a36Sopenharmony_ci
381562306a36Sopenharmony_ci			for (i = 0; i < 500; i++) {
381662306a36Sopenharmony_ci				if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
381762306a36Sopenharmony_ci					return;
381862306a36Sopenharmony_ci				if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
381962306a36Sopenharmony_ci				    AUTOLOAD_DONE)
382062306a36Sopenharmony_ci					break;
382162306a36Sopenharmony_ci				msleep(20);
382262306a36Sopenharmony_ci			}
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci			tp->rtl_ops.hw_phy_cfg(tp);
382562306a36Sopenharmony_ci
382662306a36Sopenharmony_ci			rtl8152_set_speed(tp, tp->autoneg, tp->speed,
382762306a36Sopenharmony_ci					  tp->duplex, tp->advertising);
382862306a36Sopenharmony_ci		}
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
383362306a36Sopenharmony_ci		ocp_data |= BIT(8);
383462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
383762306a36Sopenharmony_ci	}
383862306a36Sopenharmony_ci}
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_cistatic void r8156_ups_en(struct r8152 *tp, bool enable)
384162306a36Sopenharmony_ci{
384262306a36Sopenharmony_ci	u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT);
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	if (enable) {
384562306a36Sopenharmony_ci		r8156_ups_flags(tp);
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci		ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN;
384862306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
385162306a36Sopenharmony_ci		ocp_data |= UPS_FORCE_PWR_DOWN;
385262306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci		switch (tp->version) {
385562306a36Sopenharmony_ci		case RTL_VER_13:
385662306a36Sopenharmony_ci		case RTL_VER_15:
385762306a36Sopenharmony_ci			ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL);
385862306a36Sopenharmony_ci			ocp_data &= ~OOBS_POLLING;
385962306a36Sopenharmony_ci			ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data);
386062306a36Sopenharmony_ci			break;
386162306a36Sopenharmony_ci		default:
386262306a36Sopenharmony_ci			break;
386362306a36Sopenharmony_ci		}
386462306a36Sopenharmony_ci	} else {
386562306a36Sopenharmony_ci		ocp_data &= ~(UPS_EN | USP_PREWAKE);
386662306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
386962306a36Sopenharmony_ci		ocp_data &= ~UPS_FORCE_PWR_DOWN;
387062306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
387362306a36Sopenharmony_ci			tp->rtl_ops.hw_phy_cfg(tp);
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_ci			rtl8152_set_speed(tp, tp->autoneg, tp->speed,
387662306a36Sopenharmony_ci					  tp->duplex, tp->advertising);
387762306a36Sopenharmony_ci		}
387862306a36Sopenharmony_ci	}
387962306a36Sopenharmony_ci}
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_cistatic void r8153_power_cut_en(struct r8152 *tp, bool enable)
388262306a36Sopenharmony_ci{
388362306a36Sopenharmony_ci	u32 ocp_data;
388462306a36Sopenharmony_ci
388562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
388662306a36Sopenharmony_ci	if (enable)
388762306a36Sopenharmony_ci		ocp_data |= PWR_EN | PHASE2_EN;
388862306a36Sopenharmony_ci	else
388962306a36Sopenharmony_ci		ocp_data &= ~(PWR_EN | PHASE2_EN);
389062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
389362306a36Sopenharmony_ci	ocp_data &= ~PCUT_STATUS;
389462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
389562306a36Sopenharmony_ci}
389662306a36Sopenharmony_ci
389762306a36Sopenharmony_cistatic void r8153b_power_cut_en(struct r8152 *tp, bool enable)
389862306a36Sopenharmony_ci{
389962306a36Sopenharmony_ci	u32 ocp_data;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
390262306a36Sopenharmony_ci	if (enable)
390362306a36Sopenharmony_ci		ocp_data |= PWR_EN | PHASE2_EN;
390462306a36Sopenharmony_ci	else
390562306a36Sopenharmony_ci		ocp_data &= ~PWR_EN;
390662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
390762306a36Sopenharmony_ci
390862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
390962306a36Sopenharmony_ci	ocp_data &= ~PCUT_STATUS;
391062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
391162306a36Sopenharmony_ci}
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_cistatic void r8153_queue_wake(struct r8152 *tp, bool enable)
391462306a36Sopenharmony_ci{
391562306a36Sopenharmony_ci	u32 ocp_data;
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG);
391862306a36Sopenharmony_ci	if (enable)
391962306a36Sopenharmony_ci		ocp_data |= UPCOMING_RUNTIME_D3;
392062306a36Sopenharmony_ci	else
392162306a36Sopenharmony_ci		ocp_data &= ~UPCOMING_RUNTIME_D3;
392262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG, ocp_data);
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_SUSPEND_FLAG);
392562306a36Sopenharmony_ci	ocp_data &= ~LINK_CHG_EVENT;
392662306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_SUSPEND_FLAG, ocp_data);
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
392962306a36Sopenharmony_ci	ocp_data &= ~LINK_CHANGE_FLAG;
393062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
393162306a36Sopenharmony_ci}
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_cistatic bool rtl_can_wakeup(struct r8152 *tp)
393462306a36Sopenharmony_ci{
393562306a36Sopenharmony_ci	struct usb_device *udev = tp->udev;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci	return (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP);
393862306a36Sopenharmony_ci}
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_cistatic void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
394162306a36Sopenharmony_ci{
394262306a36Sopenharmony_ci	if (enable) {
394362306a36Sopenharmony_ci		u32 ocp_data;
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci		__rtl_set_wol(tp, WAKE_ANY);
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
395062306a36Sopenharmony_ci		ocp_data |= LINK_OFF_WAKE_EN;
395162306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
395462306a36Sopenharmony_ci	} else {
395562306a36Sopenharmony_ci		u32 ocp_data;
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci		__rtl_set_wol(tp, tp->saved_wolopts);
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
396262306a36Sopenharmony_ci		ocp_data &= ~LINK_OFF_WAKE_EN;
396362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
396662306a36Sopenharmony_ci	}
396762306a36Sopenharmony_ci}
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_cistatic void rtl8153_runtime_enable(struct r8152 *tp, bool enable)
397062306a36Sopenharmony_ci{
397162306a36Sopenharmony_ci	if (enable) {
397262306a36Sopenharmony_ci		r8153_u1u2en(tp, false);
397362306a36Sopenharmony_ci		r8153_u2p3en(tp, false);
397462306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, true);
397562306a36Sopenharmony_ci	} else {
397662306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, false);
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci		switch (tp->version) {
397962306a36Sopenharmony_ci		case RTL_VER_03:
398062306a36Sopenharmony_ci		case RTL_VER_04:
398162306a36Sopenharmony_ci			break;
398262306a36Sopenharmony_ci		case RTL_VER_05:
398362306a36Sopenharmony_ci		case RTL_VER_06:
398462306a36Sopenharmony_ci		default:
398562306a36Sopenharmony_ci			r8153_u2p3en(tp, true);
398662306a36Sopenharmony_ci			break;
398762306a36Sopenharmony_ci		}
398862306a36Sopenharmony_ci
398962306a36Sopenharmony_ci		r8153_u1u2en(tp, true);
399062306a36Sopenharmony_ci	}
399162306a36Sopenharmony_ci}
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_cistatic void rtl8153b_runtime_enable(struct r8152 *tp, bool enable)
399462306a36Sopenharmony_ci{
399562306a36Sopenharmony_ci	if (enable) {
399662306a36Sopenharmony_ci		r8153_queue_wake(tp, true);
399762306a36Sopenharmony_ci		r8153b_u1u2en(tp, false);
399862306a36Sopenharmony_ci		r8153_u2p3en(tp, false);
399962306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, true);
400062306a36Sopenharmony_ci		r8153b_ups_en(tp, true);
400162306a36Sopenharmony_ci	} else {
400262306a36Sopenharmony_ci		r8153b_ups_en(tp, false);
400362306a36Sopenharmony_ci		r8153_queue_wake(tp, false);
400462306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, false);
400562306a36Sopenharmony_ci		if (tp->udev->speed >= USB_SPEED_SUPER)
400662306a36Sopenharmony_ci			r8153b_u1u2en(tp, true);
400762306a36Sopenharmony_ci	}
400862306a36Sopenharmony_ci}
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_cistatic void rtl8153c_runtime_enable(struct r8152 *tp, bool enable)
401162306a36Sopenharmony_ci{
401262306a36Sopenharmony_ci	if (enable) {
401362306a36Sopenharmony_ci		r8153_queue_wake(tp, true);
401462306a36Sopenharmony_ci		r8153b_u1u2en(tp, false);
401562306a36Sopenharmony_ci		r8153_u2p3en(tp, false);
401662306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, true);
401762306a36Sopenharmony_ci		r8153c_ups_en(tp, true);
401862306a36Sopenharmony_ci	} else {
401962306a36Sopenharmony_ci		r8153c_ups_en(tp, false);
402062306a36Sopenharmony_ci		r8153_queue_wake(tp, false);
402162306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, false);
402262306a36Sopenharmony_ci		r8153b_u1u2en(tp, true);
402362306a36Sopenharmony_ci	}
402462306a36Sopenharmony_ci}
402562306a36Sopenharmony_ci
402662306a36Sopenharmony_cistatic void rtl8156_runtime_enable(struct r8152 *tp, bool enable)
402762306a36Sopenharmony_ci{
402862306a36Sopenharmony_ci	if (enable) {
402962306a36Sopenharmony_ci		r8153_queue_wake(tp, true);
403062306a36Sopenharmony_ci		r8153b_u1u2en(tp, false);
403162306a36Sopenharmony_ci		r8153_u2p3en(tp, false);
403262306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, true);
403362306a36Sopenharmony_ci	} else {
403462306a36Sopenharmony_ci		r8153_queue_wake(tp, false);
403562306a36Sopenharmony_ci		rtl_runtime_suspend_enable(tp, false);
403662306a36Sopenharmony_ci		r8153_u2p3en(tp, true);
403762306a36Sopenharmony_ci		if (tp->udev->speed >= USB_SPEED_SUPER)
403862306a36Sopenharmony_ci			r8153b_u1u2en(tp, true);
403962306a36Sopenharmony_ci	}
404062306a36Sopenharmony_ci}
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_cistatic void r8153_teredo_off(struct r8152 *tp)
404362306a36Sopenharmony_ci{
404462306a36Sopenharmony_ci	u32 ocp_data;
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	switch (tp->version) {
404762306a36Sopenharmony_ci	case RTL_VER_01:
404862306a36Sopenharmony_ci	case RTL_VER_02:
404962306a36Sopenharmony_ci	case RTL_VER_03:
405062306a36Sopenharmony_ci	case RTL_VER_04:
405162306a36Sopenharmony_ci	case RTL_VER_05:
405262306a36Sopenharmony_ci	case RTL_VER_06:
405362306a36Sopenharmony_ci	case RTL_VER_07:
405462306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
405562306a36Sopenharmony_ci		ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK |
405662306a36Sopenharmony_ci			      OOB_TEREDO_EN);
405762306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
405862306a36Sopenharmony_ci		break;
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	case RTL_VER_08:
406162306a36Sopenharmony_ci	case RTL_VER_09:
406262306a36Sopenharmony_ci	case RTL_TEST_01:
406362306a36Sopenharmony_ci	case RTL_VER_10:
406462306a36Sopenharmony_ci	case RTL_VER_11:
406562306a36Sopenharmony_ci	case RTL_VER_12:
406662306a36Sopenharmony_ci	case RTL_VER_13:
406762306a36Sopenharmony_ci	case RTL_VER_14:
406862306a36Sopenharmony_ci	case RTL_VER_15:
406962306a36Sopenharmony_ci	default:
407062306a36Sopenharmony_ci		/* The bit 0 ~ 7 are relative with teredo settings. They are
407162306a36Sopenharmony_ci		 * W1C (write 1 to clear), so set all 1 to disable it.
407262306a36Sopenharmony_ci		 */
407362306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff);
407462306a36Sopenharmony_ci		break;
407562306a36Sopenharmony_ci	}
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
407862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
407962306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
408062306a36Sopenharmony_ci}
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_cistatic void rtl_reset_bmu(struct r8152 *tp)
408362306a36Sopenharmony_ci{
408462306a36Sopenharmony_ci	u32 ocp_data;
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_BMU_RESET);
408762306a36Sopenharmony_ci	ocp_data &= ~(BMU_RESET_EP_IN | BMU_RESET_EP_OUT);
408862306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
408962306a36Sopenharmony_ci	ocp_data |= BMU_RESET_EP_IN | BMU_RESET_EP_OUT;
409062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
409162306a36Sopenharmony_ci}
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci/* Clear the bp to stop the firmware before loading a new one */
409462306a36Sopenharmony_cistatic void rtl_clear_bp(struct r8152 *tp, u16 type)
409562306a36Sopenharmony_ci{
409662306a36Sopenharmony_ci	u16 bp[16] = {0};
409762306a36Sopenharmony_ci	u16 bp_num;
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	switch (tp->version) {
410062306a36Sopenharmony_ci	case RTL_VER_08:
410162306a36Sopenharmony_ci	case RTL_VER_09:
410262306a36Sopenharmony_ci	case RTL_VER_10:
410362306a36Sopenharmony_ci	case RTL_VER_11:
410462306a36Sopenharmony_ci	case RTL_VER_12:
410562306a36Sopenharmony_ci	case RTL_VER_13:
410662306a36Sopenharmony_ci	case RTL_VER_15:
410762306a36Sopenharmony_ci		if (type == MCU_TYPE_USB) {
410862306a36Sopenharmony_ci			ocp_write_word(tp, MCU_TYPE_USB, USB_BP2_EN, 0);
410962306a36Sopenharmony_ci			bp_num = 16;
411062306a36Sopenharmony_ci			break;
411162306a36Sopenharmony_ci		}
411262306a36Sopenharmony_ci		fallthrough;
411362306a36Sopenharmony_ci	case RTL_VER_03:
411462306a36Sopenharmony_ci	case RTL_VER_04:
411562306a36Sopenharmony_ci	case RTL_VER_05:
411662306a36Sopenharmony_ci	case RTL_VER_06:
411762306a36Sopenharmony_ci		ocp_write_byte(tp, type, PLA_BP_EN, 0);
411862306a36Sopenharmony_ci		fallthrough;
411962306a36Sopenharmony_ci	case RTL_VER_01:
412062306a36Sopenharmony_ci	case RTL_VER_02:
412162306a36Sopenharmony_ci	case RTL_VER_07:
412262306a36Sopenharmony_ci		bp_num = 8;
412362306a36Sopenharmony_ci		break;
412462306a36Sopenharmony_ci	case RTL_VER_14:
412562306a36Sopenharmony_ci	default:
412662306a36Sopenharmony_ci		ocp_write_word(tp, type, USB_BP2_EN, 0);
412762306a36Sopenharmony_ci		bp_num = 16;
412862306a36Sopenharmony_ci		break;
412962306a36Sopenharmony_ci	}
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci	generic_ocp_write(tp, PLA_BP_0, BYTE_EN_DWORD, bp_num << 1, bp, type);
413262306a36Sopenharmony_ci
413362306a36Sopenharmony_ci	/* wait 3 ms to make sure the firmware is stopped */
413462306a36Sopenharmony_ci	usleep_range(3000, 6000);
413562306a36Sopenharmony_ci	ocp_write_word(tp, type, PLA_BP_BA, 0);
413662306a36Sopenharmony_ci}
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_cistatic inline void rtl_reset_ocp_base(struct r8152 *tp)
413962306a36Sopenharmony_ci{
414062306a36Sopenharmony_ci	tp->ocp_base = -1;
414162306a36Sopenharmony_ci}
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_cistatic int rtl_phy_patch_request(struct r8152 *tp, bool request, bool wait)
414462306a36Sopenharmony_ci{
414562306a36Sopenharmony_ci	u16 data, check;
414662306a36Sopenharmony_ci	int i;
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD);
414962306a36Sopenharmony_ci	if (request) {
415062306a36Sopenharmony_ci		data |= PATCH_REQUEST;
415162306a36Sopenharmony_ci		check = 0;
415262306a36Sopenharmony_ci	} else {
415362306a36Sopenharmony_ci		data &= ~PATCH_REQUEST;
415462306a36Sopenharmony_ci		check = PATCH_READY;
415562306a36Sopenharmony_ci	}
415662306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data);
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci	for (i = 0; wait && i < 5000; i++) {
415962306a36Sopenharmony_ci		u32 ocp_data;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
416262306a36Sopenharmony_ci			return -ENODEV;
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci		usleep_range(1000, 2000);
416562306a36Sopenharmony_ci		ocp_data = ocp_reg_read(tp, OCP_PHY_PATCH_STAT);
416662306a36Sopenharmony_ci		if ((ocp_data & PATCH_READY) ^ check)
416762306a36Sopenharmony_ci			break;
416862306a36Sopenharmony_ci	}
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	if (request && wait &&
417162306a36Sopenharmony_ci	    !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) {
417262306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "PHY patch request fail\n");
417362306a36Sopenharmony_ci		rtl_phy_patch_request(tp, false, false);
417462306a36Sopenharmony_ci		return -ETIME;
417562306a36Sopenharmony_ci	} else {
417662306a36Sopenharmony_ci		return 0;
417762306a36Sopenharmony_ci	}
417862306a36Sopenharmony_ci}
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_cistatic void rtl_patch_key_set(struct r8152 *tp, u16 key_addr, u16 patch_key)
418162306a36Sopenharmony_ci{
418262306a36Sopenharmony_ci	if (patch_key && key_addr) {
418362306a36Sopenharmony_ci		sram_write(tp, key_addr, patch_key);
418462306a36Sopenharmony_ci		sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK);
418562306a36Sopenharmony_ci	} else if (key_addr) {
418662306a36Sopenharmony_ci		u16 data;
418762306a36Sopenharmony_ci
418862306a36Sopenharmony_ci		sram_write(tp, 0x0000, 0x0000);
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_PHY_LOCK);
419162306a36Sopenharmony_ci		data &= ~PATCH_LOCK;
419262306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_PHY_LOCK, data);
419362306a36Sopenharmony_ci
419462306a36Sopenharmony_ci		sram_write(tp, key_addr, 0x0000);
419562306a36Sopenharmony_ci	} else {
419662306a36Sopenharmony_ci		WARN_ON_ONCE(1);
419762306a36Sopenharmony_ci	}
419862306a36Sopenharmony_ci}
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_cistatic int
420162306a36Sopenharmony_cirtl_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key, bool wait)
420262306a36Sopenharmony_ci{
420362306a36Sopenharmony_ci	if (rtl_phy_patch_request(tp, true, wait))
420462306a36Sopenharmony_ci		return -ETIME;
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	rtl_patch_key_set(tp, key_addr, patch_key);
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_ci	return 0;
420962306a36Sopenharmony_ci}
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_cistatic int rtl_post_ram_code(struct r8152 *tp, u16 key_addr, bool wait)
421262306a36Sopenharmony_ci{
421362306a36Sopenharmony_ci	rtl_patch_key_set(tp, key_addr, 0);
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_ci	rtl_phy_patch_request(tp, false, wait);
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_ci	return 0;
421862306a36Sopenharmony_ci}
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_cistatic bool rtl8152_is_fw_phy_speed_up_ok(struct r8152 *tp, struct fw_phy_speed_up *phy)
422162306a36Sopenharmony_ci{
422262306a36Sopenharmony_ci	u16 fw_offset;
422362306a36Sopenharmony_ci	u32 length;
422462306a36Sopenharmony_ci	bool rc = false;
422562306a36Sopenharmony_ci
422662306a36Sopenharmony_ci	switch (tp->version) {
422762306a36Sopenharmony_ci	case RTL_VER_01:
422862306a36Sopenharmony_ci	case RTL_VER_02:
422962306a36Sopenharmony_ci	case RTL_VER_03:
423062306a36Sopenharmony_ci	case RTL_VER_04:
423162306a36Sopenharmony_ci	case RTL_VER_05:
423262306a36Sopenharmony_ci	case RTL_VER_06:
423362306a36Sopenharmony_ci	case RTL_VER_07:
423462306a36Sopenharmony_ci	case RTL_VER_08:
423562306a36Sopenharmony_ci	case RTL_VER_09:
423662306a36Sopenharmony_ci	case RTL_VER_10:
423762306a36Sopenharmony_ci	case RTL_VER_11:
423862306a36Sopenharmony_ci	case RTL_VER_12:
423962306a36Sopenharmony_ci	case RTL_VER_14:
424062306a36Sopenharmony_ci		goto out;
424162306a36Sopenharmony_ci	case RTL_VER_13:
424262306a36Sopenharmony_ci	case RTL_VER_15:
424362306a36Sopenharmony_ci	default:
424462306a36Sopenharmony_ci		break;
424562306a36Sopenharmony_ci	}
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci	fw_offset = __le16_to_cpu(phy->fw_offset);
424862306a36Sopenharmony_ci	length = __le32_to_cpu(phy->blk_hdr.length);
424962306a36Sopenharmony_ci	if (fw_offset < sizeof(*phy) || length <= fw_offset) {
425062306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid fw_offset\n");
425162306a36Sopenharmony_ci		goto out;
425262306a36Sopenharmony_ci	}
425362306a36Sopenharmony_ci
425462306a36Sopenharmony_ci	length -= fw_offset;
425562306a36Sopenharmony_ci	if (length & 3) {
425662306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid block length\n");
425762306a36Sopenharmony_ci		goto out;
425862306a36Sopenharmony_ci	}
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci	if (__le16_to_cpu(phy->fw_reg) != 0x9A00) {
426162306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid register to load firmware\n");
426262306a36Sopenharmony_ci		goto out;
426362306a36Sopenharmony_ci	}
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	rc = true;
426662306a36Sopenharmony_ciout:
426762306a36Sopenharmony_ci	return rc;
426862306a36Sopenharmony_ci}
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_cistatic bool rtl8152_is_fw_phy_ver_ok(struct r8152 *tp, struct fw_phy_ver *ver)
427162306a36Sopenharmony_ci{
427262306a36Sopenharmony_ci	bool rc = false;
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci	switch (tp->version) {
427562306a36Sopenharmony_ci	case RTL_VER_10:
427662306a36Sopenharmony_ci	case RTL_VER_11:
427762306a36Sopenharmony_ci	case RTL_VER_12:
427862306a36Sopenharmony_ci	case RTL_VER_13:
427962306a36Sopenharmony_ci	case RTL_VER_15:
428062306a36Sopenharmony_ci		break;
428162306a36Sopenharmony_ci	default:
428262306a36Sopenharmony_ci		goto out;
428362306a36Sopenharmony_ci	}
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci	if (__le32_to_cpu(ver->blk_hdr.length) != sizeof(*ver)) {
428662306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid block length\n");
428762306a36Sopenharmony_ci		goto out;
428862306a36Sopenharmony_ci	}
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci	if (__le16_to_cpu(ver->ver.addr) != SRAM_GPHY_FW_VER) {
429162306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid phy ver addr\n");
429262306a36Sopenharmony_ci		goto out;
429362306a36Sopenharmony_ci	}
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci	rc = true;
429662306a36Sopenharmony_ciout:
429762306a36Sopenharmony_ci	return rc;
429862306a36Sopenharmony_ci}
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_cistatic bool rtl8152_is_fw_phy_fixup_ok(struct r8152 *tp, struct fw_phy_fixup *fix)
430162306a36Sopenharmony_ci{
430262306a36Sopenharmony_ci	bool rc = false;
430362306a36Sopenharmony_ci
430462306a36Sopenharmony_ci	switch (tp->version) {
430562306a36Sopenharmony_ci	case RTL_VER_10:
430662306a36Sopenharmony_ci	case RTL_VER_11:
430762306a36Sopenharmony_ci	case RTL_VER_12:
430862306a36Sopenharmony_ci	case RTL_VER_13:
430962306a36Sopenharmony_ci	case RTL_VER_15:
431062306a36Sopenharmony_ci		break;
431162306a36Sopenharmony_ci	default:
431262306a36Sopenharmony_ci		goto out;
431362306a36Sopenharmony_ci	}
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci	if (__le32_to_cpu(fix->blk_hdr.length) != sizeof(*fix)) {
431662306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid block length\n");
431762306a36Sopenharmony_ci		goto out;
431862306a36Sopenharmony_ci	}
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	if (__le16_to_cpu(fix->setting.addr) != OCP_PHY_PATCH_CMD ||
432162306a36Sopenharmony_ci	    __le16_to_cpu(fix->setting.data) != BIT(7)) {
432262306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid phy fixup\n");
432362306a36Sopenharmony_ci		goto out;
432462306a36Sopenharmony_ci	}
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci	rc = true;
432762306a36Sopenharmony_ciout:
432862306a36Sopenharmony_ci	return rc;
432962306a36Sopenharmony_ci}
433062306a36Sopenharmony_ci
433162306a36Sopenharmony_cistatic bool rtl8152_is_fw_phy_union_ok(struct r8152 *tp, struct fw_phy_union *phy)
433262306a36Sopenharmony_ci{
433362306a36Sopenharmony_ci	u16 fw_offset;
433462306a36Sopenharmony_ci	u32 length;
433562306a36Sopenharmony_ci	bool rc = false;
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci	switch (tp->version) {
433862306a36Sopenharmony_ci	case RTL_VER_10:
433962306a36Sopenharmony_ci	case RTL_VER_11:
434062306a36Sopenharmony_ci	case RTL_VER_12:
434162306a36Sopenharmony_ci	case RTL_VER_13:
434262306a36Sopenharmony_ci	case RTL_VER_15:
434362306a36Sopenharmony_ci		break;
434462306a36Sopenharmony_ci	default:
434562306a36Sopenharmony_ci		goto out;
434662306a36Sopenharmony_ci	}
434762306a36Sopenharmony_ci
434862306a36Sopenharmony_ci	fw_offset = __le16_to_cpu(phy->fw_offset);
434962306a36Sopenharmony_ci	length = __le32_to_cpu(phy->blk_hdr.length);
435062306a36Sopenharmony_ci	if (fw_offset < sizeof(*phy) || length <= fw_offset) {
435162306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid fw_offset\n");
435262306a36Sopenharmony_ci		goto out;
435362306a36Sopenharmony_ci	}
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	length -= fw_offset;
435662306a36Sopenharmony_ci	if (length & 1) {
435762306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid block length\n");
435862306a36Sopenharmony_ci		goto out;
435962306a36Sopenharmony_ci	}
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci	if (phy->pre_num > 2) {
436262306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid pre_num %d\n", phy->pre_num);
436362306a36Sopenharmony_ci		goto out;
436462306a36Sopenharmony_ci	}
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	if (phy->bp_num > 8) {
436762306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid bp_num %d\n", phy->bp_num);
436862306a36Sopenharmony_ci		goto out;
436962306a36Sopenharmony_ci	}
437062306a36Sopenharmony_ci
437162306a36Sopenharmony_ci	rc = true;
437262306a36Sopenharmony_ciout:
437362306a36Sopenharmony_ci	return rc;
437462306a36Sopenharmony_ci}
437562306a36Sopenharmony_ci
437662306a36Sopenharmony_cistatic bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy)
437762306a36Sopenharmony_ci{
437862306a36Sopenharmony_ci	u32 length;
437962306a36Sopenharmony_ci	u16 fw_offset, fw_reg, ba_reg, patch_en_addr, mode_reg, bp_start;
438062306a36Sopenharmony_ci	bool rc = false;
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci	switch (tp->version) {
438362306a36Sopenharmony_ci	case RTL_VER_04:
438462306a36Sopenharmony_ci	case RTL_VER_05:
438562306a36Sopenharmony_ci	case RTL_VER_06:
438662306a36Sopenharmony_ci		fw_reg = 0xa014;
438762306a36Sopenharmony_ci		ba_reg = 0xa012;
438862306a36Sopenharmony_ci		patch_en_addr = 0xa01a;
438962306a36Sopenharmony_ci		mode_reg = 0xb820;
439062306a36Sopenharmony_ci		bp_start = 0xa000;
439162306a36Sopenharmony_ci		break;
439262306a36Sopenharmony_ci	default:
439362306a36Sopenharmony_ci		goto out;
439462306a36Sopenharmony_ci	}
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci	fw_offset = __le16_to_cpu(phy->fw_offset);
439762306a36Sopenharmony_ci	if (fw_offset < sizeof(*phy)) {
439862306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "fw_offset too small\n");
439962306a36Sopenharmony_ci		goto out;
440062306a36Sopenharmony_ci	}
440162306a36Sopenharmony_ci
440262306a36Sopenharmony_ci	length = __le32_to_cpu(phy->blk_hdr.length);
440362306a36Sopenharmony_ci	if (length < fw_offset) {
440462306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid fw_offset\n");
440562306a36Sopenharmony_ci		goto out;
440662306a36Sopenharmony_ci	}
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_ci	length -= __le16_to_cpu(phy->fw_offset);
440962306a36Sopenharmony_ci	if (!length || (length & 1)) {
441062306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid block length\n");
441162306a36Sopenharmony_ci		goto out;
441262306a36Sopenharmony_ci	}
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_ci	if (__le16_to_cpu(phy->fw_reg) != fw_reg) {
441562306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid register to load firmware\n");
441662306a36Sopenharmony_ci		goto out;
441762306a36Sopenharmony_ci	}
441862306a36Sopenharmony_ci
441962306a36Sopenharmony_ci	if (__le16_to_cpu(phy->ba_reg) != ba_reg) {
442062306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid base address register\n");
442162306a36Sopenharmony_ci		goto out;
442262306a36Sopenharmony_ci	}
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	if (__le16_to_cpu(phy->patch_en_addr) != patch_en_addr) {
442562306a36Sopenharmony_ci		dev_err(&tp->intf->dev,
442662306a36Sopenharmony_ci			"invalid patch mode enabled register\n");
442762306a36Sopenharmony_ci		goto out;
442862306a36Sopenharmony_ci	}
442962306a36Sopenharmony_ci
443062306a36Sopenharmony_ci	if (__le16_to_cpu(phy->mode_reg) != mode_reg) {
443162306a36Sopenharmony_ci		dev_err(&tp->intf->dev,
443262306a36Sopenharmony_ci			"invalid register to switch the mode\n");
443362306a36Sopenharmony_ci		goto out;
443462306a36Sopenharmony_ci	}
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_ci	if (__le16_to_cpu(phy->bp_start) != bp_start) {
443762306a36Sopenharmony_ci		dev_err(&tp->intf->dev,
443862306a36Sopenharmony_ci			"invalid start register of break point\n");
443962306a36Sopenharmony_ci		goto out;
444062306a36Sopenharmony_ci	}
444162306a36Sopenharmony_ci
444262306a36Sopenharmony_ci	if (__le16_to_cpu(phy->bp_num) > 4) {
444362306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid break point number\n");
444462306a36Sopenharmony_ci		goto out;
444562306a36Sopenharmony_ci	}
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci	rc = true;
444862306a36Sopenharmony_ciout:
444962306a36Sopenharmony_ci	return rc;
445062306a36Sopenharmony_ci}
445162306a36Sopenharmony_ci
445262306a36Sopenharmony_cistatic bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac)
445362306a36Sopenharmony_ci{
445462306a36Sopenharmony_ci	u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset;
445562306a36Sopenharmony_ci	bool rc = false;
445662306a36Sopenharmony_ci	u32 length, type;
445762306a36Sopenharmony_ci	int i, max_bp;
445862306a36Sopenharmony_ci
445962306a36Sopenharmony_ci	type = __le32_to_cpu(mac->blk_hdr.type);
446062306a36Sopenharmony_ci	if (type == RTL_FW_PLA) {
446162306a36Sopenharmony_ci		switch (tp->version) {
446262306a36Sopenharmony_ci		case RTL_VER_01:
446362306a36Sopenharmony_ci		case RTL_VER_02:
446462306a36Sopenharmony_ci		case RTL_VER_07:
446562306a36Sopenharmony_ci			fw_reg = 0xf800;
446662306a36Sopenharmony_ci			bp_ba_addr = PLA_BP_BA;
446762306a36Sopenharmony_ci			bp_en_addr = 0;
446862306a36Sopenharmony_ci			bp_start = PLA_BP_0;
446962306a36Sopenharmony_ci			max_bp = 8;
447062306a36Sopenharmony_ci			break;
447162306a36Sopenharmony_ci		case RTL_VER_03:
447262306a36Sopenharmony_ci		case RTL_VER_04:
447362306a36Sopenharmony_ci		case RTL_VER_05:
447462306a36Sopenharmony_ci		case RTL_VER_06:
447562306a36Sopenharmony_ci		case RTL_VER_08:
447662306a36Sopenharmony_ci		case RTL_VER_09:
447762306a36Sopenharmony_ci		case RTL_VER_11:
447862306a36Sopenharmony_ci		case RTL_VER_12:
447962306a36Sopenharmony_ci		case RTL_VER_13:
448062306a36Sopenharmony_ci		case RTL_VER_15:
448162306a36Sopenharmony_ci			fw_reg = 0xf800;
448262306a36Sopenharmony_ci			bp_ba_addr = PLA_BP_BA;
448362306a36Sopenharmony_ci			bp_en_addr = PLA_BP_EN;
448462306a36Sopenharmony_ci			bp_start = PLA_BP_0;
448562306a36Sopenharmony_ci			max_bp = 8;
448662306a36Sopenharmony_ci			break;
448762306a36Sopenharmony_ci		case RTL_VER_14:
448862306a36Sopenharmony_ci			fw_reg = 0xf800;
448962306a36Sopenharmony_ci			bp_ba_addr = PLA_BP_BA;
449062306a36Sopenharmony_ci			bp_en_addr = USB_BP2_EN;
449162306a36Sopenharmony_ci			bp_start = PLA_BP_0;
449262306a36Sopenharmony_ci			max_bp = 16;
449362306a36Sopenharmony_ci			break;
449462306a36Sopenharmony_ci		default:
449562306a36Sopenharmony_ci			goto out;
449662306a36Sopenharmony_ci		}
449762306a36Sopenharmony_ci	} else if (type == RTL_FW_USB) {
449862306a36Sopenharmony_ci		switch (tp->version) {
449962306a36Sopenharmony_ci		case RTL_VER_03:
450062306a36Sopenharmony_ci		case RTL_VER_04:
450162306a36Sopenharmony_ci		case RTL_VER_05:
450262306a36Sopenharmony_ci		case RTL_VER_06:
450362306a36Sopenharmony_ci			fw_reg = 0xf800;
450462306a36Sopenharmony_ci			bp_ba_addr = USB_BP_BA;
450562306a36Sopenharmony_ci			bp_en_addr = USB_BP_EN;
450662306a36Sopenharmony_ci			bp_start = USB_BP_0;
450762306a36Sopenharmony_ci			max_bp = 8;
450862306a36Sopenharmony_ci			break;
450962306a36Sopenharmony_ci		case RTL_VER_08:
451062306a36Sopenharmony_ci		case RTL_VER_09:
451162306a36Sopenharmony_ci		case RTL_VER_11:
451262306a36Sopenharmony_ci		case RTL_VER_12:
451362306a36Sopenharmony_ci		case RTL_VER_13:
451462306a36Sopenharmony_ci		case RTL_VER_14:
451562306a36Sopenharmony_ci		case RTL_VER_15:
451662306a36Sopenharmony_ci			fw_reg = 0xe600;
451762306a36Sopenharmony_ci			bp_ba_addr = USB_BP_BA;
451862306a36Sopenharmony_ci			bp_en_addr = USB_BP2_EN;
451962306a36Sopenharmony_ci			bp_start = USB_BP_0;
452062306a36Sopenharmony_ci			max_bp = 16;
452162306a36Sopenharmony_ci			break;
452262306a36Sopenharmony_ci		case RTL_VER_01:
452362306a36Sopenharmony_ci		case RTL_VER_02:
452462306a36Sopenharmony_ci		case RTL_VER_07:
452562306a36Sopenharmony_ci		default:
452662306a36Sopenharmony_ci			goto out;
452762306a36Sopenharmony_ci		}
452862306a36Sopenharmony_ci	} else {
452962306a36Sopenharmony_ci		goto out;
453062306a36Sopenharmony_ci	}
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	fw_offset = __le16_to_cpu(mac->fw_offset);
453362306a36Sopenharmony_ci	if (fw_offset < sizeof(*mac)) {
453462306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "fw_offset too small\n");
453562306a36Sopenharmony_ci		goto out;
453662306a36Sopenharmony_ci	}
453762306a36Sopenharmony_ci
453862306a36Sopenharmony_ci	length = __le32_to_cpu(mac->blk_hdr.length);
453962306a36Sopenharmony_ci	if (length < fw_offset) {
454062306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid fw_offset\n");
454162306a36Sopenharmony_ci		goto out;
454262306a36Sopenharmony_ci	}
454362306a36Sopenharmony_ci
454462306a36Sopenharmony_ci	length -= fw_offset;
454562306a36Sopenharmony_ci	if (length < 4 || (length & 3)) {
454662306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid block length\n");
454762306a36Sopenharmony_ci		goto out;
454862306a36Sopenharmony_ci	}
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	if (__le16_to_cpu(mac->fw_reg) != fw_reg) {
455162306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid register to load firmware\n");
455262306a36Sopenharmony_ci		goto out;
455362306a36Sopenharmony_ci	}
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci	if (__le16_to_cpu(mac->bp_ba_addr) != bp_ba_addr) {
455662306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid base address register\n");
455762306a36Sopenharmony_ci		goto out;
455862306a36Sopenharmony_ci	}
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	if (__le16_to_cpu(mac->bp_en_addr) != bp_en_addr) {
456162306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid enabled mask register\n");
456262306a36Sopenharmony_ci		goto out;
456362306a36Sopenharmony_ci	}
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	if (__le16_to_cpu(mac->bp_start) != bp_start) {
456662306a36Sopenharmony_ci		dev_err(&tp->intf->dev,
456762306a36Sopenharmony_ci			"invalid start register of break point\n");
456862306a36Sopenharmony_ci		goto out;
456962306a36Sopenharmony_ci	}
457062306a36Sopenharmony_ci
457162306a36Sopenharmony_ci	if (__le16_to_cpu(mac->bp_num) > max_bp) {
457262306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "invalid break point number\n");
457362306a36Sopenharmony_ci		goto out;
457462306a36Sopenharmony_ci	}
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci	for (i = __le16_to_cpu(mac->bp_num); i < max_bp; i++) {
457762306a36Sopenharmony_ci		if (mac->bp[i]) {
457862306a36Sopenharmony_ci			dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i);
457962306a36Sopenharmony_ci			goto out;
458062306a36Sopenharmony_ci		}
458162306a36Sopenharmony_ci	}
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_ci	rc = true;
458462306a36Sopenharmony_ciout:
458562306a36Sopenharmony_ci	return rc;
458662306a36Sopenharmony_ci}
458762306a36Sopenharmony_ci
458862306a36Sopenharmony_ci/* Verify the checksum for the firmware file. It is calculated from the version
458962306a36Sopenharmony_ci * field to the end of the file. Compare the result with the checksum field to
459062306a36Sopenharmony_ci * make sure the file is correct.
459162306a36Sopenharmony_ci */
459262306a36Sopenharmony_cistatic long rtl8152_fw_verify_checksum(struct r8152 *tp,
459362306a36Sopenharmony_ci				       struct fw_header *fw_hdr, size_t size)
459462306a36Sopenharmony_ci{
459562306a36Sopenharmony_ci	unsigned char checksum[sizeof(fw_hdr->checksum)];
459662306a36Sopenharmony_ci	struct crypto_shash *alg;
459762306a36Sopenharmony_ci	struct shash_desc *sdesc;
459862306a36Sopenharmony_ci	size_t len;
459962306a36Sopenharmony_ci	long rc;
460062306a36Sopenharmony_ci
460162306a36Sopenharmony_ci	alg = crypto_alloc_shash("sha256", 0, 0);
460262306a36Sopenharmony_ci	if (IS_ERR(alg)) {
460362306a36Sopenharmony_ci		rc = PTR_ERR(alg);
460462306a36Sopenharmony_ci		goto out;
460562306a36Sopenharmony_ci	}
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_ci	if (crypto_shash_digestsize(alg) != sizeof(fw_hdr->checksum)) {
460862306a36Sopenharmony_ci		rc = -EFAULT;
460962306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "digestsize incorrect (%u)\n",
461062306a36Sopenharmony_ci			crypto_shash_digestsize(alg));
461162306a36Sopenharmony_ci		goto free_shash;
461262306a36Sopenharmony_ci	}
461362306a36Sopenharmony_ci
461462306a36Sopenharmony_ci	len = sizeof(*sdesc) + crypto_shash_descsize(alg);
461562306a36Sopenharmony_ci	sdesc = kmalloc(len, GFP_KERNEL);
461662306a36Sopenharmony_ci	if (!sdesc) {
461762306a36Sopenharmony_ci		rc = -ENOMEM;
461862306a36Sopenharmony_ci		goto free_shash;
461962306a36Sopenharmony_ci	}
462062306a36Sopenharmony_ci	sdesc->tfm = alg;
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci	len = size - sizeof(fw_hdr->checksum);
462362306a36Sopenharmony_ci	rc = crypto_shash_digest(sdesc, fw_hdr->version, len, checksum);
462462306a36Sopenharmony_ci	kfree(sdesc);
462562306a36Sopenharmony_ci	if (rc)
462662306a36Sopenharmony_ci		goto free_shash;
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ci	if (memcmp(fw_hdr->checksum, checksum, sizeof(fw_hdr->checksum))) {
462962306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "checksum fail\n");
463062306a36Sopenharmony_ci		rc = -EFAULT;
463162306a36Sopenharmony_ci	}
463262306a36Sopenharmony_ci
463362306a36Sopenharmony_cifree_shash:
463462306a36Sopenharmony_ci	crypto_free_shash(alg);
463562306a36Sopenharmony_ciout:
463662306a36Sopenharmony_ci	return rc;
463762306a36Sopenharmony_ci}
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_cistatic long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw)
464062306a36Sopenharmony_ci{
464162306a36Sopenharmony_ci	const struct firmware *fw = rtl_fw->fw;
464262306a36Sopenharmony_ci	struct fw_header *fw_hdr = (struct fw_header *)fw->data;
464362306a36Sopenharmony_ci	unsigned long fw_flags = 0;
464462306a36Sopenharmony_ci	long ret = -EFAULT;
464562306a36Sopenharmony_ci	int i;
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci	if (fw->size < sizeof(*fw_hdr)) {
464862306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "file too small\n");
464962306a36Sopenharmony_ci		goto fail;
465062306a36Sopenharmony_ci	}
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci	ret = rtl8152_fw_verify_checksum(tp, fw_hdr, fw->size);
465362306a36Sopenharmony_ci	if (ret)
465462306a36Sopenharmony_ci		goto fail;
465562306a36Sopenharmony_ci
465662306a36Sopenharmony_ci	ret = -EFAULT;
465762306a36Sopenharmony_ci
465862306a36Sopenharmony_ci	for (i = sizeof(*fw_hdr); i < fw->size;) {
465962306a36Sopenharmony_ci		struct fw_block *block = (struct fw_block *)&fw->data[i];
466062306a36Sopenharmony_ci		u32 type;
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci		if ((i + sizeof(*block)) > fw->size)
466362306a36Sopenharmony_ci			goto fail;
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci		type = __le32_to_cpu(block->type);
466662306a36Sopenharmony_ci		switch (type) {
466762306a36Sopenharmony_ci		case RTL_FW_END:
466862306a36Sopenharmony_ci			if (__le32_to_cpu(block->length) != sizeof(*block))
466962306a36Sopenharmony_ci				goto fail;
467062306a36Sopenharmony_ci			goto fw_end;
467162306a36Sopenharmony_ci		case RTL_FW_PLA:
467262306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_PLA, &fw_flags)) {
467362306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
467462306a36Sopenharmony_ci					"multiple PLA firmware encountered");
467562306a36Sopenharmony_ci				goto fail;
467662306a36Sopenharmony_ci			}
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci			if (!rtl8152_is_fw_mac_ok(tp, (struct fw_mac *)block)) {
467962306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
468062306a36Sopenharmony_ci					"check PLA firmware failed\n");
468162306a36Sopenharmony_ci				goto fail;
468262306a36Sopenharmony_ci			}
468362306a36Sopenharmony_ci			__set_bit(FW_FLAGS_PLA, &fw_flags);
468462306a36Sopenharmony_ci			break;
468562306a36Sopenharmony_ci		case RTL_FW_USB:
468662306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_USB, &fw_flags)) {
468762306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
468862306a36Sopenharmony_ci					"multiple USB firmware encountered");
468962306a36Sopenharmony_ci				goto fail;
469062306a36Sopenharmony_ci			}
469162306a36Sopenharmony_ci
469262306a36Sopenharmony_ci			if (!rtl8152_is_fw_mac_ok(tp, (struct fw_mac *)block)) {
469362306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
469462306a36Sopenharmony_ci					"check USB firmware failed\n");
469562306a36Sopenharmony_ci				goto fail;
469662306a36Sopenharmony_ci			}
469762306a36Sopenharmony_ci			__set_bit(FW_FLAGS_USB, &fw_flags);
469862306a36Sopenharmony_ci			break;
469962306a36Sopenharmony_ci		case RTL_FW_PHY_START:
470062306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_START, &fw_flags) ||
470162306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC, &fw_flags) ||
470262306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
470362306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
470462306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
470562306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC, &fw_flags) ||
470662306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
470762306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
470862306a36Sopenharmony_ci					"check PHY_START fail\n");
470962306a36Sopenharmony_ci				goto fail;
471062306a36Sopenharmony_ci			}
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_ci			if (__le32_to_cpu(block->length) != sizeof(struct fw_phy_patch_key)) {
471362306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
471462306a36Sopenharmony_ci					"Invalid length for PHY_START\n");
471562306a36Sopenharmony_ci				goto fail;
471662306a36Sopenharmony_ci			}
471762306a36Sopenharmony_ci			__set_bit(FW_FLAGS_START, &fw_flags);
471862306a36Sopenharmony_ci			break;
471962306a36Sopenharmony_ci		case RTL_FW_PHY_STOP:
472062306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_STOP, &fw_flags) ||
472162306a36Sopenharmony_ci			    !test_bit(FW_FLAGS_START, &fw_flags)) {
472262306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
472362306a36Sopenharmony_ci					"Check PHY_STOP fail\n");
472462306a36Sopenharmony_ci				goto fail;
472562306a36Sopenharmony_ci			}
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_ci			if (__le32_to_cpu(block->length) != sizeof(*block)) {
472862306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
472962306a36Sopenharmony_ci					"Invalid length for PHY_STOP\n");
473062306a36Sopenharmony_ci				goto fail;
473162306a36Sopenharmony_ci			}
473262306a36Sopenharmony_ci			__set_bit(FW_FLAGS_STOP, &fw_flags);
473362306a36Sopenharmony_ci			break;
473462306a36Sopenharmony_ci		case RTL_FW_PHY_NC:
473562306a36Sopenharmony_ci			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
473662306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
473762306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
473862306a36Sopenharmony_ci					"check PHY_NC fail\n");
473962306a36Sopenharmony_ci				goto fail;
474062306a36Sopenharmony_ci			}
474162306a36Sopenharmony_ci
474262306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_NC, &fw_flags)) {
474362306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
474462306a36Sopenharmony_ci					"multiple PHY NC encountered\n");
474562306a36Sopenharmony_ci				goto fail;
474662306a36Sopenharmony_ci			}
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_nc_ok(tp, (struct fw_phy_nc *)block)) {
474962306a36Sopenharmony_ci				dev_err(&tp->intf->dev,
475062306a36Sopenharmony_ci					"check PHY NC firmware failed\n");
475162306a36Sopenharmony_ci				goto fail;
475262306a36Sopenharmony_ci			}
475362306a36Sopenharmony_ci			__set_bit(FW_FLAGS_NC, &fw_flags);
475462306a36Sopenharmony_ci			break;
475562306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_NC:
475662306a36Sopenharmony_ci			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
475762306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
475862306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
475962306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
476062306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC, &fw_flags) ||
476162306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
476262306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "PHY_UNION_NC out of order\n");
476362306a36Sopenharmony_ci				goto fail;
476462306a36Sopenharmony_ci			}
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_NC, &fw_flags)) {
476762306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY_UNION_NC encountered\n");
476862306a36Sopenharmony_ci				goto fail;
476962306a36Sopenharmony_ci			}
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
477262306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY_UNION_NC failed\n");
477362306a36Sopenharmony_ci				goto fail;
477462306a36Sopenharmony_ci			}
477562306a36Sopenharmony_ci			__set_bit(FW_FLAGS_NC, &fw_flags);
477662306a36Sopenharmony_ci			break;
477762306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_NC1:
477862306a36Sopenharmony_ci			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
477962306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
478062306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
478162306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC, &fw_flags) ||
478262306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
478362306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "PHY_UNION_NC1 out of order\n");
478462306a36Sopenharmony_ci				goto fail;
478562306a36Sopenharmony_ci			}
478662306a36Sopenharmony_ci
478762306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_NC1, &fw_flags)) {
478862306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY NC1 encountered\n");
478962306a36Sopenharmony_ci				goto fail;
479062306a36Sopenharmony_ci			}
479162306a36Sopenharmony_ci
479262306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
479362306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY_UNION_NC1 failed\n");
479462306a36Sopenharmony_ci				goto fail;
479562306a36Sopenharmony_ci			}
479662306a36Sopenharmony_ci			__set_bit(FW_FLAGS_NC1, &fw_flags);
479762306a36Sopenharmony_ci			break;
479862306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_NC2:
479962306a36Sopenharmony_ci			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
480062306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
480162306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC, &fw_flags) ||
480262306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
480362306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "PHY_UNION_NC2 out of order\n");
480462306a36Sopenharmony_ci				goto fail;
480562306a36Sopenharmony_ci			}
480662306a36Sopenharmony_ci
480762306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_NC2, &fw_flags)) {
480862306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY NC2 encountered\n");
480962306a36Sopenharmony_ci				goto fail;
481062306a36Sopenharmony_ci			}
481162306a36Sopenharmony_ci
481262306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
481362306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY_UNION_NC2 failed\n");
481462306a36Sopenharmony_ci				goto fail;
481562306a36Sopenharmony_ci			}
481662306a36Sopenharmony_ci			__set_bit(FW_FLAGS_NC2, &fw_flags);
481762306a36Sopenharmony_ci			break;
481862306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_UC2:
481962306a36Sopenharmony_ci			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
482062306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC, &fw_flags) ||
482162306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
482262306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "PHY_UNION_UC2 out of order\n");
482362306a36Sopenharmony_ci				goto fail;
482462306a36Sopenharmony_ci			}
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_UC2, &fw_flags)) {
482762306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY UC2 encountered\n");
482862306a36Sopenharmony_ci				goto fail;
482962306a36Sopenharmony_ci			}
483062306a36Sopenharmony_ci
483162306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
483262306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY_UNION_UC2 failed\n");
483362306a36Sopenharmony_ci				goto fail;
483462306a36Sopenharmony_ci			}
483562306a36Sopenharmony_ci			__set_bit(FW_FLAGS_UC2, &fw_flags);
483662306a36Sopenharmony_ci			break;
483762306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_UC:
483862306a36Sopenharmony_ci			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
483962306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
484062306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "PHY_UNION_UC out of order\n");
484162306a36Sopenharmony_ci				goto fail;
484262306a36Sopenharmony_ci			}
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_UC, &fw_flags)) {
484562306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY UC encountered\n");
484662306a36Sopenharmony_ci				goto fail;
484762306a36Sopenharmony_ci			}
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
485062306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY_UNION_UC failed\n");
485162306a36Sopenharmony_ci				goto fail;
485262306a36Sopenharmony_ci			}
485362306a36Sopenharmony_ci			__set_bit(FW_FLAGS_UC, &fw_flags);
485462306a36Sopenharmony_ci			break;
485562306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_MISC:
485662306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
485762306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check RTL_FW_PHY_UNION_MISC failed\n");
485862306a36Sopenharmony_ci				goto fail;
485962306a36Sopenharmony_ci			}
486062306a36Sopenharmony_ci			break;
486162306a36Sopenharmony_ci		case RTL_FW_PHY_FIXUP:
486262306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_fixup_ok(tp, (struct fw_phy_fixup *)block)) {
486362306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY fixup failed\n");
486462306a36Sopenharmony_ci				goto fail;
486562306a36Sopenharmony_ci			}
486662306a36Sopenharmony_ci			break;
486762306a36Sopenharmony_ci		case RTL_FW_PHY_SPEED_UP:
486862306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_SPEED_UP, &fw_flags)) {
486962306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY firmware encountered");
487062306a36Sopenharmony_ci				goto fail;
487162306a36Sopenharmony_ci			}
487262306a36Sopenharmony_ci
487362306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_speed_up_ok(tp, (struct fw_phy_speed_up *)block)) {
487462306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY speed up failed\n");
487562306a36Sopenharmony_ci				goto fail;
487662306a36Sopenharmony_ci			}
487762306a36Sopenharmony_ci			__set_bit(FW_FLAGS_SPEED_UP, &fw_flags);
487862306a36Sopenharmony_ci			break;
487962306a36Sopenharmony_ci		case RTL_FW_PHY_VER:
488062306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_START, &fw_flags) ||
488162306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC, &fw_flags) ||
488262306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
488362306a36Sopenharmony_ci			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
488462306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
488562306a36Sopenharmony_ci			    test_bit(FW_FLAGS_UC, &fw_flags) ||
488662306a36Sopenharmony_ci			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
488762306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "Invalid order to set PHY version\n");
488862306a36Sopenharmony_ci				goto fail;
488962306a36Sopenharmony_ci			}
489062306a36Sopenharmony_ci
489162306a36Sopenharmony_ci			if (test_bit(FW_FLAGS_VER, &fw_flags)) {
489262306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "multiple PHY version encountered");
489362306a36Sopenharmony_ci				goto fail;
489462306a36Sopenharmony_ci			}
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_ci			if (!rtl8152_is_fw_phy_ver_ok(tp, (struct fw_phy_ver *)block)) {
489762306a36Sopenharmony_ci				dev_err(&tp->intf->dev, "check PHY version failed\n");
489862306a36Sopenharmony_ci				goto fail;
489962306a36Sopenharmony_ci			}
490062306a36Sopenharmony_ci			__set_bit(FW_FLAGS_VER, &fw_flags);
490162306a36Sopenharmony_ci			break;
490262306a36Sopenharmony_ci		default:
490362306a36Sopenharmony_ci			dev_warn(&tp->intf->dev, "Unknown type %u is found\n",
490462306a36Sopenharmony_ci				 type);
490562306a36Sopenharmony_ci			break;
490662306a36Sopenharmony_ci		}
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci		/* next block */
490962306a36Sopenharmony_ci		i += ALIGN(__le32_to_cpu(block->length), 8);
491062306a36Sopenharmony_ci	}
491162306a36Sopenharmony_ci
491262306a36Sopenharmony_cifw_end:
491362306a36Sopenharmony_ci	if (test_bit(FW_FLAGS_START, &fw_flags) && !test_bit(FW_FLAGS_STOP, &fw_flags)) {
491462306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "without PHY_STOP\n");
491562306a36Sopenharmony_ci		goto fail;
491662306a36Sopenharmony_ci	}
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	return 0;
491962306a36Sopenharmony_cifail:
492062306a36Sopenharmony_ci	return ret;
492162306a36Sopenharmony_ci}
492262306a36Sopenharmony_ci
492362306a36Sopenharmony_cistatic void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy, bool wait)
492462306a36Sopenharmony_ci{
492562306a36Sopenharmony_ci	u32 len;
492662306a36Sopenharmony_ci	u8 *data;
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
492962306a36Sopenharmony_ci
493062306a36Sopenharmony_ci	if (sram_read(tp, SRAM_GPHY_FW_VER) >= __le16_to_cpu(phy->version)) {
493162306a36Sopenharmony_ci		dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
493262306a36Sopenharmony_ci		return;
493362306a36Sopenharmony_ci	}
493462306a36Sopenharmony_ci
493562306a36Sopenharmony_ci	len = __le32_to_cpu(phy->blk_hdr.length);
493662306a36Sopenharmony_ci	len -= __le16_to_cpu(phy->fw_offset);
493762306a36Sopenharmony_ci	data = (u8 *)phy + __le16_to_cpu(phy->fw_offset);
493862306a36Sopenharmony_ci
493962306a36Sopenharmony_ci	if (rtl_phy_patch_request(tp, true, wait))
494062306a36Sopenharmony_ci		return;
494162306a36Sopenharmony_ci
494262306a36Sopenharmony_ci	while (len) {
494362306a36Sopenharmony_ci		u32 ocp_data, size;
494462306a36Sopenharmony_ci		int i;
494562306a36Sopenharmony_ci
494662306a36Sopenharmony_ci		if (len < 2048)
494762306a36Sopenharmony_ci			size = len;
494862306a36Sopenharmony_ci		else
494962306a36Sopenharmony_ci			size = 2048;
495062306a36Sopenharmony_ci
495162306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL);
495262306a36Sopenharmony_ci		ocp_data |= GPHY_PATCH_DONE | BACKUP_RESTRORE;
495362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL, ocp_data);
495462306a36Sopenharmony_ci
495562306a36Sopenharmony_ci		generic_ocp_write(tp, __le16_to_cpu(phy->fw_reg), 0xff, size, data, MCU_TYPE_USB);
495662306a36Sopenharmony_ci
495762306a36Sopenharmony_ci		data += size;
495862306a36Sopenharmony_ci		len -= size;
495962306a36Sopenharmony_ci
496062306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL);
496162306a36Sopenharmony_ci		ocp_data |= POL_GPHY_PATCH;
496262306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL, ocp_data);
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci		for (i = 0; i < 1000; i++) {
496562306a36Sopenharmony_ci			if (!(ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL) & POL_GPHY_PATCH))
496662306a36Sopenharmony_ci				break;
496762306a36Sopenharmony_ci		}
496862306a36Sopenharmony_ci
496962306a36Sopenharmony_ci		if (i == 1000) {
497062306a36Sopenharmony_ci			dev_err(&tp->intf->dev, "ram code speedup mode timeout\n");
497162306a36Sopenharmony_ci			break;
497262306a36Sopenharmony_ci		}
497362306a36Sopenharmony_ci	}
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_ci	rtl_phy_patch_request(tp, false, wait);
497862306a36Sopenharmony_ci
497962306a36Sopenharmony_ci	if (sram_read(tp, SRAM_GPHY_FW_VER) == __le16_to_cpu(phy->version))
498062306a36Sopenharmony_ci		dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
498162306a36Sopenharmony_ci	else
498262306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "ram code speedup mode fail\n");
498362306a36Sopenharmony_ci}
498462306a36Sopenharmony_ci
498562306a36Sopenharmony_cistatic int rtl8152_fw_phy_ver(struct r8152 *tp, struct fw_phy_ver *phy_ver)
498662306a36Sopenharmony_ci{
498762306a36Sopenharmony_ci	u16 ver_addr, ver;
498862306a36Sopenharmony_ci
498962306a36Sopenharmony_ci	ver_addr = __le16_to_cpu(phy_ver->ver.addr);
499062306a36Sopenharmony_ci	ver = __le16_to_cpu(phy_ver->ver.data);
499162306a36Sopenharmony_ci
499262306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
499362306a36Sopenharmony_ci
499462306a36Sopenharmony_ci	if (sram_read(tp, ver_addr) >= ver) {
499562306a36Sopenharmony_ci		dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
499662306a36Sopenharmony_ci		return 0;
499762306a36Sopenharmony_ci	}
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci	sram_write(tp, ver_addr, ver);
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci	dev_dbg(&tp->intf->dev, "PHY firmware version %x\n", ver);
500262306a36Sopenharmony_ci
500362306a36Sopenharmony_ci	return ver;
500462306a36Sopenharmony_ci}
500562306a36Sopenharmony_ci
500662306a36Sopenharmony_cistatic void rtl8152_fw_phy_fixup(struct r8152 *tp, struct fw_phy_fixup *fix)
500762306a36Sopenharmony_ci{
500862306a36Sopenharmony_ci	u16 addr, data;
500962306a36Sopenharmony_ci
501062306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
501162306a36Sopenharmony_ci
501262306a36Sopenharmony_ci	addr = __le16_to_cpu(fix->setting.addr);
501362306a36Sopenharmony_ci	data = ocp_reg_read(tp, addr);
501462306a36Sopenharmony_ci
501562306a36Sopenharmony_ci	switch (__le16_to_cpu(fix->bit_cmd)) {
501662306a36Sopenharmony_ci	case FW_FIXUP_AND:
501762306a36Sopenharmony_ci		data &= __le16_to_cpu(fix->setting.data);
501862306a36Sopenharmony_ci		break;
501962306a36Sopenharmony_ci	case FW_FIXUP_OR:
502062306a36Sopenharmony_ci		data |= __le16_to_cpu(fix->setting.data);
502162306a36Sopenharmony_ci		break;
502262306a36Sopenharmony_ci	case FW_FIXUP_NOT:
502362306a36Sopenharmony_ci		data &= ~__le16_to_cpu(fix->setting.data);
502462306a36Sopenharmony_ci		break;
502562306a36Sopenharmony_ci	case FW_FIXUP_XOR:
502662306a36Sopenharmony_ci		data ^= __le16_to_cpu(fix->setting.data);
502762306a36Sopenharmony_ci		break;
502862306a36Sopenharmony_ci	default:
502962306a36Sopenharmony_ci		return;
503062306a36Sopenharmony_ci	}
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	ocp_reg_write(tp, addr, data);
503362306a36Sopenharmony_ci
503462306a36Sopenharmony_ci	dev_dbg(&tp->intf->dev, "applied ocp %x %x\n", addr, data);
503562306a36Sopenharmony_ci}
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_cistatic void rtl8152_fw_phy_union_apply(struct r8152 *tp, struct fw_phy_union *phy)
503862306a36Sopenharmony_ci{
503962306a36Sopenharmony_ci	__le16 *data;
504062306a36Sopenharmony_ci	u32 length;
504162306a36Sopenharmony_ci	int i, num;
504262306a36Sopenharmony_ci
504362306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
504462306a36Sopenharmony_ci
504562306a36Sopenharmony_ci	num = phy->pre_num;
504662306a36Sopenharmony_ci	for (i = 0; i < num; i++)
504762306a36Sopenharmony_ci		sram_write(tp, __le16_to_cpu(phy->pre_set[i].addr),
504862306a36Sopenharmony_ci			   __le16_to_cpu(phy->pre_set[i].data));
504962306a36Sopenharmony_ci
505062306a36Sopenharmony_ci	length = __le32_to_cpu(phy->blk_hdr.length);
505162306a36Sopenharmony_ci	length -= __le16_to_cpu(phy->fw_offset);
505262306a36Sopenharmony_ci	num = length / 2;
505362306a36Sopenharmony_ci	data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset));
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg));
505662306a36Sopenharmony_ci	for (i = 0; i < num; i++)
505762306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i]));
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci	num = phy->bp_num;
506062306a36Sopenharmony_ci	for (i = 0; i < num; i++)
506162306a36Sopenharmony_ci		sram_write(tp, __le16_to_cpu(phy->bp[i].addr), __le16_to_cpu(phy->bp[i].data));
506262306a36Sopenharmony_ci
506362306a36Sopenharmony_ci	if (phy->bp_num && phy->bp_en.addr)
506462306a36Sopenharmony_ci		sram_write(tp, __le16_to_cpu(phy->bp_en.addr), __le16_to_cpu(phy->bp_en.data));
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
506762306a36Sopenharmony_ci}
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_cistatic void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy)
507062306a36Sopenharmony_ci{
507162306a36Sopenharmony_ci	u16 mode_reg, bp_index;
507262306a36Sopenharmony_ci	u32 length, i, num;
507362306a36Sopenharmony_ci	__le16 *data;
507462306a36Sopenharmony_ci
507562306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
507662306a36Sopenharmony_ci
507762306a36Sopenharmony_ci	mode_reg = __le16_to_cpu(phy->mode_reg);
507862306a36Sopenharmony_ci	sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre));
507962306a36Sopenharmony_ci	sram_write(tp, __le16_to_cpu(phy->ba_reg),
508062306a36Sopenharmony_ci		   __le16_to_cpu(phy->ba_data));
508162306a36Sopenharmony_ci
508262306a36Sopenharmony_ci	length = __le32_to_cpu(phy->blk_hdr.length);
508362306a36Sopenharmony_ci	length -= __le16_to_cpu(phy->fw_offset);
508462306a36Sopenharmony_ci	num = length / 2;
508562306a36Sopenharmony_ci	data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset));
508662306a36Sopenharmony_ci
508762306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg));
508862306a36Sopenharmony_ci	for (i = 0; i < num; i++)
508962306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i]));
509062306a36Sopenharmony_ci
509162306a36Sopenharmony_ci	sram_write(tp, __le16_to_cpu(phy->patch_en_addr),
509262306a36Sopenharmony_ci		   __le16_to_cpu(phy->patch_en_value));
509362306a36Sopenharmony_ci
509462306a36Sopenharmony_ci	bp_index = __le16_to_cpu(phy->bp_start);
509562306a36Sopenharmony_ci	num = __le16_to_cpu(phy->bp_num);
509662306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
509762306a36Sopenharmony_ci		sram_write(tp, bp_index, __le16_to_cpu(phy->bp[i]));
509862306a36Sopenharmony_ci		bp_index += 2;
509962306a36Sopenharmony_ci	}
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_post));
510262306a36Sopenharmony_ci
510362306a36Sopenharmony_ci	dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
510462306a36Sopenharmony_ci}
510562306a36Sopenharmony_ci
510662306a36Sopenharmony_cistatic void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac)
510762306a36Sopenharmony_ci{
510862306a36Sopenharmony_ci	u16 bp_en_addr, type, fw_ver_reg;
510962306a36Sopenharmony_ci	u32 length;
511062306a36Sopenharmony_ci	u8 *data;
511162306a36Sopenharmony_ci
511262306a36Sopenharmony_ci	switch (__le32_to_cpu(mac->blk_hdr.type)) {
511362306a36Sopenharmony_ci	case RTL_FW_PLA:
511462306a36Sopenharmony_ci		type = MCU_TYPE_PLA;
511562306a36Sopenharmony_ci		break;
511662306a36Sopenharmony_ci	case RTL_FW_USB:
511762306a36Sopenharmony_ci		type = MCU_TYPE_USB;
511862306a36Sopenharmony_ci		break;
511962306a36Sopenharmony_ci	default:
512062306a36Sopenharmony_ci		return;
512162306a36Sopenharmony_ci	}
512262306a36Sopenharmony_ci
512362306a36Sopenharmony_ci	fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg);
512462306a36Sopenharmony_ci	if (fw_ver_reg && ocp_read_byte(tp, MCU_TYPE_USB, fw_ver_reg) >= mac->fw_ver_data) {
512562306a36Sopenharmony_ci		dev_dbg(&tp->intf->dev, "%s firmware has been the newest\n", type ? "PLA" : "USB");
512662306a36Sopenharmony_ci		return;
512762306a36Sopenharmony_ci	}
512862306a36Sopenharmony_ci
512962306a36Sopenharmony_ci	rtl_clear_bp(tp, type);
513062306a36Sopenharmony_ci
513162306a36Sopenharmony_ci	/* Enable backup/restore of MACDBG. This is required after clearing PLA
513262306a36Sopenharmony_ci	 * break points and before applying the PLA firmware.
513362306a36Sopenharmony_ci	 */
513462306a36Sopenharmony_ci	if (tp->version == RTL_VER_04 && type == MCU_TYPE_PLA &&
513562306a36Sopenharmony_ci	    !(ocp_read_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST) & DEBUG_OE)) {
513662306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_PRE, DEBUG_LTSSM);
513762306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM);
513862306a36Sopenharmony_ci	}
513962306a36Sopenharmony_ci
514062306a36Sopenharmony_ci	length = __le32_to_cpu(mac->blk_hdr.length);
514162306a36Sopenharmony_ci	length -= __le16_to_cpu(mac->fw_offset);
514262306a36Sopenharmony_ci
514362306a36Sopenharmony_ci	data = (u8 *)mac;
514462306a36Sopenharmony_ci	data += __le16_to_cpu(mac->fw_offset);
514562306a36Sopenharmony_ci
514662306a36Sopenharmony_ci	generic_ocp_write(tp, __le16_to_cpu(mac->fw_reg), 0xff, length, data,
514762306a36Sopenharmony_ci			  type);
514862306a36Sopenharmony_ci
514962306a36Sopenharmony_ci	ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr),
515062306a36Sopenharmony_ci		       __le16_to_cpu(mac->bp_ba_value));
515162306a36Sopenharmony_ci
515262306a36Sopenharmony_ci	generic_ocp_write(tp, __le16_to_cpu(mac->bp_start), BYTE_EN_DWORD,
515362306a36Sopenharmony_ci			  __le16_to_cpu(mac->bp_num) << 1, mac->bp, type);
515462306a36Sopenharmony_ci
515562306a36Sopenharmony_ci	bp_en_addr = __le16_to_cpu(mac->bp_en_addr);
515662306a36Sopenharmony_ci	if (bp_en_addr)
515762306a36Sopenharmony_ci		ocp_write_word(tp, type, bp_en_addr,
515862306a36Sopenharmony_ci			       __le16_to_cpu(mac->bp_en_value));
515962306a36Sopenharmony_ci
516062306a36Sopenharmony_ci	if (fw_ver_reg)
516162306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg,
516262306a36Sopenharmony_ci			       mac->fw_ver_data);
516362306a36Sopenharmony_ci
516462306a36Sopenharmony_ci	dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info);
516562306a36Sopenharmony_ci}
516662306a36Sopenharmony_ci
516762306a36Sopenharmony_cistatic void rtl8152_apply_firmware(struct r8152 *tp, bool power_cut)
516862306a36Sopenharmony_ci{
516962306a36Sopenharmony_ci	struct rtl_fw *rtl_fw = &tp->rtl_fw;
517062306a36Sopenharmony_ci	const struct firmware *fw;
517162306a36Sopenharmony_ci	struct fw_header *fw_hdr;
517262306a36Sopenharmony_ci	struct fw_phy_patch_key *key;
517362306a36Sopenharmony_ci	u16 key_addr = 0;
517462306a36Sopenharmony_ci	int i, patch_phy = 1;
517562306a36Sopenharmony_ci
517662306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(rtl_fw->fw))
517762306a36Sopenharmony_ci		return;
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_ci	fw = rtl_fw->fw;
518062306a36Sopenharmony_ci	fw_hdr = (struct fw_header *)fw->data;
518162306a36Sopenharmony_ci
518262306a36Sopenharmony_ci	if (rtl_fw->pre_fw)
518362306a36Sopenharmony_ci		rtl_fw->pre_fw(tp);
518462306a36Sopenharmony_ci
518562306a36Sopenharmony_ci	for (i = offsetof(struct fw_header, blocks); i < fw->size;) {
518662306a36Sopenharmony_ci		struct fw_block *block = (struct fw_block *)&fw->data[i];
518762306a36Sopenharmony_ci
518862306a36Sopenharmony_ci		switch (__le32_to_cpu(block->type)) {
518962306a36Sopenharmony_ci		case RTL_FW_END:
519062306a36Sopenharmony_ci			goto post_fw;
519162306a36Sopenharmony_ci		case RTL_FW_PLA:
519262306a36Sopenharmony_ci		case RTL_FW_USB:
519362306a36Sopenharmony_ci			rtl8152_fw_mac_apply(tp, (struct fw_mac *)block);
519462306a36Sopenharmony_ci			break;
519562306a36Sopenharmony_ci		case RTL_FW_PHY_START:
519662306a36Sopenharmony_ci			if (!patch_phy)
519762306a36Sopenharmony_ci				break;
519862306a36Sopenharmony_ci			key = (struct fw_phy_patch_key *)block;
519962306a36Sopenharmony_ci			key_addr = __le16_to_cpu(key->key_reg);
520062306a36Sopenharmony_ci			rtl_pre_ram_code(tp, key_addr, __le16_to_cpu(key->key_data), !power_cut);
520162306a36Sopenharmony_ci			break;
520262306a36Sopenharmony_ci		case RTL_FW_PHY_STOP:
520362306a36Sopenharmony_ci			if (!patch_phy)
520462306a36Sopenharmony_ci				break;
520562306a36Sopenharmony_ci			WARN_ON(!key_addr);
520662306a36Sopenharmony_ci			rtl_post_ram_code(tp, key_addr, !power_cut);
520762306a36Sopenharmony_ci			break;
520862306a36Sopenharmony_ci		case RTL_FW_PHY_NC:
520962306a36Sopenharmony_ci			rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block);
521062306a36Sopenharmony_ci			break;
521162306a36Sopenharmony_ci		case RTL_FW_PHY_VER:
521262306a36Sopenharmony_ci			patch_phy = rtl8152_fw_phy_ver(tp, (struct fw_phy_ver *)block);
521362306a36Sopenharmony_ci			break;
521462306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_NC:
521562306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_NC1:
521662306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_NC2:
521762306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_UC2:
521862306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_UC:
521962306a36Sopenharmony_ci		case RTL_FW_PHY_UNION_MISC:
522062306a36Sopenharmony_ci			if (patch_phy)
522162306a36Sopenharmony_ci				rtl8152_fw_phy_union_apply(tp, (struct fw_phy_union *)block);
522262306a36Sopenharmony_ci			break;
522362306a36Sopenharmony_ci		case RTL_FW_PHY_FIXUP:
522462306a36Sopenharmony_ci			if (patch_phy)
522562306a36Sopenharmony_ci				rtl8152_fw_phy_fixup(tp, (struct fw_phy_fixup *)block);
522662306a36Sopenharmony_ci			break;
522762306a36Sopenharmony_ci		case RTL_FW_PHY_SPEED_UP:
522862306a36Sopenharmony_ci			rtl_ram_code_speed_up(tp, (struct fw_phy_speed_up *)block, !power_cut);
522962306a36Sopenharmony_ci			break;
523062306a36Sopenharmony_ci		default:
523162306a36Sopenharmony_ci			break;
523262306a36Sopenharmony_ci		}
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_ci		i += ALIGN(__le32_to_cpu(block->length), 8);
523562306a36Sopenharmony_ci	}
523662306a36Sopenharmony_ci
523762306a36Sopenharmony_cipost_fw:
523862306a36Sopenharmony_ci	if (rtl_fw->post_fw)
523962306a36Sopenharmony_ci		rtl_fw->post_fw(tp);
524062306a36Sopenharmony_ci
524162306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
524262306a36Sopenharmony_ci	strscpy(rtl_fw->version, fw_hdr->version, RTL_VER_SIZE);
524362306a36Sopenharmony_ci	dev_info(&tp->intf->dev, "load %s successfully\n", rtl_fw->version);
524462306a36Sopenharmony_ci}
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_cistatic void rtl8152_release_firmware(struct r8152 *tp)
524762306a36Sopenharmony_ci{
524862306a36Sopenharmony_ci	struct rtl_fw *rtl_fw = &tp->rtl_fw;
524962306a36Sopenharmony_ci
525062306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(rtl_fw->fw)) {
525162306a36Sopenharmony_ci		release_firmware(rtl_fw->fw);
525262306a36Sopenharmony_ci		rtl_fw->fw = NULL;
525362306a36Sopenharmony_ci	}
525462306a36Sopenharmony_ci}
525562306a36Sopenharmony_ci
525662306a36Sopenharmony_cistatic int rtl8152_request_firmware(struct r8152 *tp)
525762306a36Sopenharmony_ci{
525862306a36Sopenharmony_ci	struct rtl_fw *rtl_fw = &tp->rtl_fw;
525962306a36Sopenharmony_ci	long rc;
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_ci	if (rtl_fw->fw || !rtl_fw->fw_name) {
526262306a36Sopenharmony_ci		dev_info(&tp->intf->dev, "skip request firmware\n");
526362306a36Sopenharmony_ci		rc = 0;
526462306a36Sopenharmony_ci		goto result;
526562306a36Sopenharmony_ci	}
526662306a36Sopenharmony_ci
526762306a36Sopenharmony_ci	rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, &tp->intf->dev);
526862306a36Sopenharmony_ci	if (rc < 0)
526962306a36Sopenharmony_ci		goto result;
527062306a36Sopenharmony_ci
527162306a36Sopenharmony_ci	rc = rtl8152_check_firmware(tp, rtl_fw);
527262306a36Sopenharmony_ci	if (rc < 0)
527362306a36Sopenharmony_ci		release_firmware(rtl_fw->fw);
527462306a36Sopenharmony_ci
527562306a36Sopenharmony_ciresult:
527662306a36Sopenharmony_ci	if (rc) {
527762306a36Sopenharmony_ci		rtl_fw->fw = ERR_PTR(rc);
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_ci		dev_warn(&tp->intf->dev,
528062306a36Sopenharmony_ci			 "unable to load firmware patch %s (%ld)\n",
528162306a36Sopenharmony_ci			 rtl_fw->fw_name, rc);
528262306a36Sopenharmony_ci	}
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	return rc;
528562306a36Sopenharmony_ci}
528662306a36Sopenharmony_ci
528762306a36Sopenharmony_cistatic void r8152_aldps_en(struct r8152 *tp, bool enable)
528862306a36Sopenharmony_ci{
528962306a36Sopenharmony_ci	if (enable) {
529062306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
529162306a36Sopenharmony_ci						    LINKENA | DIS_SDSAVE);
529262306a36Sopenharmony_ci	} else {
529362306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA |
529462306a36Sopenharmony_ci						    DIS_SDSAVE);
529562306a36Sopenharmony_ci		msleep(20);
529662306a36Sopenharmony_ci	}
529762306a36Sopenharmony_ci}
529862306a36Sopenharmony_ci
529962306a36Sopenharmony_cistatic inline void r8152_mmd_indirect(struct r8152 *tp, u16 dev, u16 reg)
530062306a36Sopenharmony_ci{
530162306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | dev);
530262306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_DATA, reg);
530362306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | dev);
530462306a36Sopenharmony_ci}
530562306a36Sopenharmony_ci
530662306a36Sopenharmony_cistatic u16 r8152_mmd_read(struct r8152 *tp, u16 dev, u16 reg)
530762306a36Sopenharmony_ci{
530862306a36Sopenharmony_ci	u16 data;
530962306a36Sopenharmony_ci
531062306a36Sopenharmony_ci	r8152_mmd_indirect(tp, dev, reg);
531162306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_EEE_DATA);
531262306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_AR, 0x0000);
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci	return data;
531562306a36Sopenharmony_ci}
531662306a36Sopenharmony_ci
531762306a36Sopenharmony_cistatic void r8152_mmd_write(struct r8152 *tp, u16 dev, u16 reg, u16 data)
531862306a36Sopenharmony_ci{
531962306a36Sopenharmony_ci	r8152_mmd_indirect(tp, dev, reg);
532062306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_DATA, data);
532162306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_AR, 0x0000);
532262306a36Sopenharmony_ci}
532362306a36Sopenharmony_ci
532462306a36Sopenharmony_cistatic void r8152_eee_en(struct r8152 *tp, bool enable)
532562306a36Sopenharmony_ci{
532662306a36Sopenharmony_ci	u16 config1, config2, config3;
532762306a36Sopenharmony_ci	u32 ocp_data;
532862306a36Sopenharmony_ci
532962306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR);
533062306a36Sopenharmony_ci	config1 = ocp_reg_read(tp, OCP_EEE_CONFIG1) & ~sd_rise_time_mask;
533162306a36Sopenharmony_ci	config2 = ocp_reg_read(tp, OCP_EEE_CONFIG2);
533262306a36Sopenharmony_ci	config3 = ocp_reg_read(tp, OCP_EEE_CONFIG3) & ~fast_snr_mask;
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci	if (enable) {
533562306a36Sopenharmony_ci		ocp_data |= EEE_RX_EN | EEE_TX_EN;
533662306a36Sopenharmony_ci		config1 |= EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | RX_QUIET_EN;
533762306a36Sopenharmony_ci		config1 |= sd_rise_time(1);
533862306a36Sopenharmony_ci		config2 |= RG_DACQUIET_EN | RG_LDVQUIET_EN;
533962306a36Sopenharmony_ci		config3 |= fast_snr(42);
534062306a36Sopenharmony_ci	} else {
534162306a36Sopenharmony_ci		ocp_data &= ~(EEE_RX_EN | EEE_TX_EN);
534262306a36Sopenharmony_ci		config1 &= ~(EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN |
534362306a36Sopenharmony_ci			     RX_QUIET_EN);
534462306a36Sopenharmony_ci		config1 |= sd_rise_time(7);
534562306a36Sopenharmony_ci		config2 &= ~(RG_DACQUIET_EN | RG_LDVQUIET_EN);
534662306a36Sopenharmony_ci		config3 |= fast_snr(511);
534762306a36Sopenharmony_ci	}
534862306a36Sopenharmony_ci
534962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data);
535062306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_CONFIG1, config1);
535162306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_CONFIG2, config2);
535262306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_CONFIG3, config3);
535362306a36Sopenharmony_ci}
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_cistatic void r8153_eee_en(struct r8152 *tp, bool enable)
535662306a36Sopenharmony_ci{
535762306a36Sopenharmony_ci	u32 ocp_data;
535862306a36Sopenharmony_ci	u16 config;
535962306a36Sopenharmony_ci
536062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR);
536162306a36Sopenharmony_ci	config = ocp_reg_read(tp, OCP_EEE_CFG);
536262306a36Sopenharmony_ci
536362306a36Sopenharmony_ci	if (enable) {
536462306a36Sopenharmony_ci		ocp_data |= EEE_RX_EN | EEE_TX_EN;
536562306a36Sopenharmony_ci		config |= EEE10_EN;
536662306a36Sopenharmony_ci	} else {
536762306a36Sopenharmony_ci		ocp_data &= ~(EEE_RX_EN | EEE_TX_EN);
536862306a36Sopenharmony_ci		config &= ~EEE10_EN;
536962306a36Sopenharmony_ci	}
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data);
537262306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_CFG, config);
537362306a36Sopenharmony_ci
537462306a36Sopenharmony_ci	tp->ups_info.eee = enable;
537562306a36Sopenharmony_ci}
537662306a36Sopenharmony_ci
537762306a36Sopenharmony_cistatic void r8156_eee_en(struct r8152 *tp, bool enable)
537862306a36Sopenharmony_ci{
537962306a36Sopenharmony_ci	u16 config;
538062306a36Sopenharmony_ci
538162306a36Sopenharmony_ci	r8153_eee_en(tp, enable);
538262306a36Sopenharmony_ci
538362306a36Sopenharmony_ci	config = ocp_reg_read(tp, OCP_EEE_ADV2);
538462306a36Sopenharmony_ci
538562306a36Sopenharmony_ci	if (enable)
538662306a36Sopenharmony_ci		config |= MDIO_EEE_2_5GT;
538762306a36Sopenharmony_ci	else
538862306a36Sopenharmony_ci		config &= ~MDIO_EEE_2_5GT;
538962306a36Sopenharmony_ci
539062306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_EEE_ADV2, config);
539162306a36Sopenharmony_ci}
539262306a36Sopenharmony_ci
539362306a36Sopenharmony_cistatic void rtl_eee_enable(struct r8152 *tp, bool enable)
539462306a36Sopenharmony_ci{
539562306a36Sopenharmony_ci	switch (tp->version) {
539662306a36Sopenharmony_ci	case RTL_VER_01:
539762306a36Sopenharmony_ci	case RTL_VER_02:
539862306a36Sopenharmony_ci	case RTL_VER_07:
539962306a36Sopenharmony_ci		if (enable) {
540062306a36Sopenharmony_ci			r8152_eee_en(tp, true);
540162306a36Sopenharmony_ci			r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV,
540262306a36Sopenharmony_ci					tp->eee_adv);
540362306a36Sopenharmony_ci		} else {
540462306a36Sopenharmony_ci			r8152_eee_en(tp, false);
540562306a36Sopenharmony_ci			r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
540662306a36Sopenharmony_ci		}
540762306a36Sopenharmony_ci		break;
540862306a36Sopenharmony_ci	case RTL_VER_03:
540962306a36Sopenharmony_ci	case RTL_VER_04:
541062306a36Sopenharmony_ci	case RTL_VER_05:
541162306a36Sopenharmony_ci	case RTL_VER_06:
541262306a36Sopenharmony_ci	case RTL_VER_08:
541362306a36Sopenharmony_ci	case RTL_VER_09:
541462306a36Sopenharmony_ci	case RTL_VER_14:
541562306a36Sopenharmony_ci		if (enable) {
541662306a36Sopenharmony_ci			r8153_eee_en(tp, true);
541762306a36Sopenharmony_ci			ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv);
541862306a36Sopenharmony_ci		} else {
541962306a36Sopenharmony_ci			r8153_eee_en(tp, false);
542062306a36Sopenharmony_ci			ocp_reg_write(tp, OCP_EEE_ADV, 0);
542162306a36Sopenharmony_ci		}
542262306a36Sopenharmony_ci		break;
542362306a36Sopenharmony_ci	case RTL_VER_10:
542462306a36Sopenharmony_ci	case RTL_VER_11:
542562306a36Sopenharmony_ci	case RTL_VER_12:
542662306a36Sopenharmony_ci	case RTL_VER_13:
542762306a36Sopenharmony_ci	case RTL_VER_15:
542862306a36Sopenharmony_ci		if (enable) {
542962306a36Sopenharmony_ci			r8156_eee_en(tp, true);
543062306a36Sopenharmony_ci			ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv);
543162306a36Sopenharmony_ci		} else {
543262306a36Sopenharmony_ci			r8156_eee_en(tp, false);
543362306a36Sopenharmony_ci			ocp_reg_write(tp, OCP_EEE_ADV, 0);
543462306a36Sopenharmony_ci		}
543562306a36Sopenharmony_ci		break;
543662306a36Sopenharmony_ci	default:
543762306a36Sopenharmony_ci		break;
543862306a36Sopenharmony_ci	}
543962306a36Sopenharmony_ci}
544062306a36Sopenharmony_ci
544162306a36Sopenharmony_cistatic void r8152b_enable_fc(struct r8152 *tp)
544262306a36Sopenharmony_ci{
544362306a36Sopenharmony_ci	u16 anar;
544462306a36Sopenharmony_ci
544562306a36Sopenharmony_ci	anar = r8152_mdio_read(tp, MII_ADVERTISE);
544662306a36Sopenharmony_ci	anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
544762306a36Sopenharmony_ci	r8152_mdio_write(tp, MII_ADVERTISE, anar);
544862306a36Sopenharmony_ci
544962306a36Sopenharmony_ci	tp->ups_info.flow_control = true;
545062306a36Sopenharmony_ci}
545162306a36Sopenharmony_ci
545262306a36Sopenharmony_cistatic void rtl8152_disable(struct r8152 *tp)
545362306a36Sopenharmony_ci{
545462306a36Sopenharmony_ci	r8152_aldps_en(tp, false);
545562306a36Sopenharmony_ci	rtl_disable(tp);
545662306a36Sopenharmony_ci	r8152_aldps_en(tp, true);
545762306a36Sopenharmony_ci}
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_cistatic void r8152b_hw_phy_cfg(struct r8152 *tp)
546062306a36Sopenharmony_ci{
546162306a36Sopenharmony_ci	rtl8152_apply_firmware(tp, false);
546262306a36Sopenharmony_ci	rtl_eee_enable(tp, tp->eee_en);
546362306a36Sopenharmony_ci	r8152_aldps_en(tp, true);
546462306a36Sopenharmony_ci	r8152b_enable_fc(tp);
546562306a36Sopenharmony_ci
546662306a36Sopenharmony_ci	set_bit(PHY_RESET, &tp->flags);
546762306a36Sopenharmony_ci}
546862306a36Sopenharmony_ci
546962306a36Sopenharmony_cistatic void wait_oob_link_list_ready(struct r8152 *tp)
547062306a36Sopenharmony_ci{
547162306a36Sopenharmony_ci	u32 ocp_data;
547262306a36Sopenharmony_ci	int i;
547362306a36Sopenharmony_ci
547462306a36Sopenharmony_ci	for (i = 0; i < 1000; i++) {
547562306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
547662306a36Sopenharmony_ci			break;
547762306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
547862306a36Sopenharmony_ci		if (ocp_data & LINK_LIST_READY)
547962306a36Sopenharmony_ci			break;
548062306a36Sopenharmony_ci		usleep_range(1000, 2000);
548162306a36Sopenharmony_ci	}
548262306a36Sopenharmony_ci}
548362306a36Sopenharmony_ci
548462306a36Sopenharmony_cistatic void r8156b_wait_loading_flash(struct r8152 *tp)
548562306a36Sopenharmony_ci{
548662306a36Sopenharmony_ci	if ((ocp_read_word(tp, MCU_TYPE_PLA, PLA_GPHY_CTRL) & GPHY_FLASH) &&
548762306a36Sopenharmony_ci	    !(ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL) & BYPASS_FLASH)) {
548862306a36Sopenharmony_ci		int i;
548962306a36Sopenharmony_ci
549062306a36Sopenharmony_ci		for (i = 0; i < 100; i++) {
549162306a36Sopenharmony_ci			if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
549262306a36Sopenharmony_ci				break;
549362306a36Sopenharmony_ci			if (ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL) & GPHY_PATCH_DONE)
549462306a36Sopenharmony_ci				break;
549562306a36Sopenharmony_ci			usleep_range(1000, 2000);
549662306a36Sopenharmony_ci		}
549762306a36Sopenharmony_ci	}
549862306a36Sopenharmony_ci}
549962306a36Sopenharmony_ci
550062306a36Sopenharmony_cistatic void r8152b_exit_oob(struct r8152 *tp)
550162306a36Sopenharmony_ci{
550262306a36Sopenharmony_ci	u32 ocp_data;
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
550562306a36Sopenharmony_ci	ocp_data &= ~RCR_ACPT_ALL;
550662306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
550762306a36Sopenharmony_ci
550862306a36Sopenharmony_ci	rxdy_gated_en(tp, true);
550962306a36Sopenharmony_ci	r8153_teredo_off(tp);
551062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
551162306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
551262306a36Sopenharmony_ci
551362306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
551462306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
551562306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
551662306a36Sopenharmony_ci
551762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
551862306a36Sopenharmony_ci	ocp_data &= ~MCU_BORW_EN;
551962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
552262306a36Sopenharmony_ci
552362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
552462306a36Sopenharmony_ci	ocp_data |= RE_INIT_LL;
552562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
552662306a36Sopenharmony_ci
552762306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
552862306a36Sopenharmony_ci
552962306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
553062306a36Sopenharmony_ci
553162306a36Sopenharmony_ci	/* rx share fifo credit full threshold */
553262306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
553362306a36Sopenharmony_ci
553462306a36Sopenharmony_ci	if (tp->udev->speed == USB_SPEED_FULL ||
553562306a36Sopenharmony_ci	    tp->udev->speed == USB_SPEED_LOW) {
553662306a36Sopenharmony_ci		/* rx share fifo credit near full threshold */
553762306a36Sopenharmony_ci		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
553862306a36Sopenharmony_ci				RXFIFO_THR2_FULL);
553962306a36Sopenharmony_ci		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
554062306a36Sopenharmony_ci				RXFIFO_THR3_FULL);
554162306a36Sopenharmony_ci	} else {
554262306a36Sopenharmony_ci		/* rx share fifo credit near full threshold */
554362306a36Sopenharmony_ci		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
554462306a36Sopenharmony_ci				RXFIFO_THR2_HIGH);
554562306a36Sopenharmony_ci		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
554662306a36Sopenharmony_ci				RXFIFO_THR3_HIGH);
554762306a36Sopenharmony_ci	}
554862306a36Sopenharmony_ci
554962306a36Sopenharmony_ci	/* TX share fifo free credit full threshold */
555062306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
555162306a36Sopenharmony_ci
555262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
555362306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
555462306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
555562306a36Sopenharmony_ci			TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
555662306a36Sopenharmony_ci
555762306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
555862306a36Sopenharmony_ci
555962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
556062306a36Sopenharmony_ci
556162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
556262306a36Sopenharmony_ci	ocp_data |= TCR0_AUTO_FIFO;
556362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
556462306a36Sopenharmony_ci}
556562306a36Sopenharmony_ci
556662306a36Sopenharmony_cistatic void r8152b_enter_oob(struct r8152 *tp)
556762306a36Sopenharmony_ci{
556862306a36Sopenharmony_ci	u32 ocp_data;
556962306a36Sopenharmony_ci
557062306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
557162306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
557262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
557362306a36Sopenharmony_ci
557462306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
557562306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
557662306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
557762306a36Sopenharmony_ci
557862306a36Sopenharmony_ci	rtl_disable(tp);
557962306a36Sopenharmony_ci
558062306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
558162306a36Sopenharmony_ci
558262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
558362306a36Sopenharmony_ci	ocp_data |= RE_INIT_LL;
558462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
558562306a36Sopenharmony_ci
558662306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
558762306a36Sopenharmony_ci
558862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
558962306a36Sopenharmony_ci
559062306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, true);
559162306a36Sopenharmony_ci
559262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
559362306a36Sopenharmony_ci	ocp_data |= ALDPS_PROXY_MODE;
559462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
559562306a36Sopenharmony_ci
559662306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
559762306a36Sopenharmony_ci	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
559862306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
559962306a36Sopenharmony_ci
560062306a36Sopenharmony_ci	rxdy_gated_en(tp, false);
560162306a36Sopenharmony_ci
560262306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
560362306a36Sopenharmony_ci	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
560462306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
560562306a36Sopenharmony_ci}
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_cistatic int r8153_pre_firmware_1(struct r8152 *tp)
560862306a36Sopenharmony_ci{
560962306a36Sopenharmony_ci	int i;
561062306a36Sopenharmony_ci
561162306a36Sopenharmony_ci	/* Wait till the WTD timer is ready. It would take at most 104 ms. */
561262306a36Sopenharmony_ci	for (i = 0; i < 104; i++) {
561362306a36Sopenharmony_ci		u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_WDT1_CTRL);
561462306a36Sopenharmony_ci
561562306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
561662306a36Sopenharmony_ci			return -ENODEV;
561762306a36Sopenharmony_ci		if (!(ocp_data & WTD1_EN))
561862306a36Sopenharmony_ci			break;
561962306a36Sopenharmony_ci		usleep_range(1000, 2000);
562062306a36Sopenharmony_ci	}
562162306a36Sopenharmony_ci
562262306a36Sopenharmony_ci	return 0;
562362306a36Sopenharmony_ci}
562462306a36Sopenharmony_ci
562562306a36Sopenharmony_cistatic int r8153_post_firmware_1(struct r8152 *tp)
562662306a36Sopenharmony_ci{
562762306a36Sopenharmony_ci	/* set USB_BP_4 to support USB_SPEED_SUPER only */
562862306a36Sopenharmony_ci	if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER)
562962306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_BP_4, BP4_SUPER_ONLY);
563062306a36Sopenharmony_ci
563162306a36Sopenharmony_ci	/* reset UPHY timer to 36 ms */
563262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16);
563362306a36Sopenharmony_ci
563462306a36Sopenharmony_ci	return 0;
563562306a36Sopenharmony_ci}
563662306a36Sopenharmony_ci
563762306a36Sopenharmony_cistatic int r8153_pre_firmware_2(struct r8152 *tp)
563862306a36Sopenharmony_ci{
563962306a36Sopenharmony_ci	u32 ocp_data;
564062306a36Sopenharmony_ci
564162306a36Sopenharmony_ci	r8153_pre_firmware_1(tp);
564262306a36Sopenharmony_ci
564362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0);
564462306a36Sopenharmony_ci	ocp_data &= ~FW_FIX_SUSPEND;
564562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data);
564662306a36Sopenharmony_ci
564762306a36Sopenharmony_ci	return 0;
564862306a36Sopenharmony_ci}
564962306a36Sopenharmony_ci
565062306a36Sopenharmony_cistatic int r8153_post_firmware_2(struct r8152 *tp)
565162306a36Sopenharmony_ci{
565262306a36Sopenharmony_ci	u32 ocp_data;
565362306a36Sopenharmony_ci
565462306a36Sopenharmony_ci	/* enable bp0 if support USB_SPEED_SUPER only */
565562306a36Sopenharmony_ci	if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) {
565662306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN);
565762306a36Sopenharmony_ci		ocp_data |= BIT(0);
565862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data);
565962306a36Sopenharmony_ci	}
566062306a36Sopenharmony_ci
566162306a36Sopenharmony_ci	/* reset UPHY timer to 36 ms */
566262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16);
566362306a36Sopenharmony_ci
566462306a36Sopenharmony_ci	/* enable U3P3 check, set the counter to 4 */
566562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, U3P3_CHECK_EN | 4);
566662306a36Sopenharmony_ci
566762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0);
566862306a36Sopenharmony_ci	ocp_data |= FW_FIX_SUSPEND;
566962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data);
567062306a36Sopenharmony_ci
567162306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
567262306a36Sopenharmony_ci	ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
567362306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
567462306a36Sopenharmony_ci
567562306a36Sopenharmony_ci	return 0;
567662306a36Sopenharmony_ci}
567762306a36Sopenharmony_ci
567862306a36Sopenharmony_cistatic int r8153_post_firmware_3(struct r8152 *tp)
567962306a36Sopenharmony_ci{
568062306a36Sopenharmony_ci	u32 ocp_data;
568162306a36Sopenharmony_ci
568262306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
568362306a36Sopenharmony_ci	ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
568462306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
568562306a36Sopenharmony_ci
568662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
568762306a36Sopenharmony_ci	ocp_data |= FW_IP_RESET_EN;
568862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
568962306a36Sopenharmony_ci
569062306a36Sopenharmony_ci	return 0;
569162306a36Sopenharmony_ci}
569262306a36Sopenharmony_ci
569362306a36Sopenharmony_cistatic int r8153b_pre_firmware_1(struct r8152 *tp)
569462306a36Sopenharmony_ci{
569562306a36Sopenharmony_ci	/* enable fc timer and set timer to 1 second. */
569662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER,
569762306a36Sopenharmony_ci		       CTRL_TIMER_EN | (1000 / 8));
569862306a36Sopenharmony_ci
569962306a36Sopenharmony_ci	return 0;
570062306a36Sopenharmony_ci}
570162306a36Sopenharmony_ci
570262306a36Sopenharmony_cistatic int r8153b_post_firmware_1(struct r8152 *tp)
570362306a36Sopenharmony_ci{
570462306a36Sopenharmony_ci	u32 ocp_data;
570562306a36Sopenharmony_ci
570662306a36Sopenharmony_ci	/* enable bp0 for RTL8153-BND */
570762306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1);
570862306a36Sopenharmony_ci	if (ocp_data & BND_MASK) {
570962306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN);
571062306a36Sopenharmony_ci		ocp_data |= BIT(0);
571162306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data);
571262306a36Sopenharmony_ci	}
571362306a36Sopenharmony_ci
571462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL);
571562306a36Sopenharmony_ci	ocp_data |= FLOW_CTRL_PATCH_OPT;
571662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data);
571762306a36Sopenharmony_ci
571862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
571962306a36Sopenharmony_ci	ocp_data |= FC_PATCH_TASK;
572062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
572162306a36Sopenharmony_ci
572262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
572362306a36Sopenharmony_ci	ocp_data |= FW_IP_RESET_EN;
572462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
572562306a36Sopenharmony_ci
572662306a36Sopenharmony_ci	return 0;
572762306a36Sopenharmony_ci}
572862306a36Sopenharmony_ci
572962306a36Sopenharmony_cistatic int r8153c_post_firmware_1(struct r8152 *tp)
573062306a36Sopenharmony_ci{
573162306a36Sopenharmony_ci	u32 ocp_data;
573262306a36Sopenharmony_ci
573362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL);
573462306a36Sopenharmony_ci	ocp_data |= FLOW_CTRL_PATCH_2;
573562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data);
573662306a36Sopenharmony_ci
573762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
573862306a36Sopenharmony_ci	ocp_data |= FC_PATCH_TASK;
573962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
574062306a36Sopenharmony_ci
574162306a36Sopenharmony_ci	return 0;
574262306a36Sopenharmony_ci}
574362306a36Sopenharmony_ci
574462306a36Sopenharmony_cistatic int r8156a_post_firmware_1(struct r8152 *tp)
574562306a36Sopenharmony_ci{
574662306a36Sopenharmony_ci	u32 ocp_data;
574762306a36Sopenharmony_ci
574862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
574962306a36Sopenharmony_ci	ocp_data |= FW_IP_RESET_EN;
575062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
575162306a36Sopenharmony_ci
575262306a36Sopenharmony_ci	/* Modify U3PHY parameter for compatibility issue */
575362306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPHY3_MDCMDIO, 0x4026840e);
575462306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPHY3_MDCMDIO, 0x4001acc9);
575562306a36Sopenharmony_ci
575662306a36Sopenharmony_ci	return 0;
575762306a36Sopenharmony_ci}
575862306a36Sopenharmony_ci
575962306a36Sopenharmony_cistatic void r8153_aldps_en(struct r8152 *tp, bool enable)
576062306a36Sopenharmony_ci{
576162306a36Sopenharmony_ci	u16 data;
576262306a36Sopenharmony_ci
576362306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_POWER_CFG);
576462306a36Sopenharmony_ci	if (enable) {
576562306a36Sopenharmony_ci		data |= EN_ALDPS;
576662306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_POWER_CFG, data);
576762306a36Sopenharmony_ci	} else {
576862306a36Sopenharmony_ci		int i;
576962306a36Sopenharmony_ci
577062306a36Sopenharmony_ci		data &= ~EN_ALDPS;
577162306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_POWER_CFG, data);
577262306a36Sopenharmony_ci		for (i = 0; i < 20; i++) {
577362306a36Sopenharmony_ci			if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
577462306a36Sopenharmony_ci				return;
577562306a36Sopenharmony_ci			usleep_range(1000, 2000);
577662306a36Sopenharmony_ci			if (ocp_read_word(tp, MCU_TYPE_PLA, 0xe000) & 0x0100)
577762306a36Sopenharmony_ci				break;
577862306a36Sopenharmony_ci		}
577962306a36Sopenharmony_ci	}
578062306a36Sopenharmony_ci
578162306a36Sopenharmony_ci	tp->ups_info.aldps = enable;
578262306a36Sopenharmony_ci}
578362306a36Sopenharmony_ci
578462306a36Sopenharmony_cistatic void r8153_hw_phy_cfg(struct r8152 *tp)
578562306a36Sopenharmony_ci{
578662306a36Sopenharmony_ci	u32 ocp_data;
578762306a36Sopenharmony_ci	u16 data;
578862306a36Sopenharmony_ci
578962306a36Sopenharmony_ci	/* disable ALDPS before updating the PHY parameters */
579062306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
579162306a36Sopenharmony_ci
579262306a36Sopenharmony_ci	/* disable EEE before updating the PHY parameters */
579362306a36Sopenharmony_ci	rtl_eee_enable(tp, false);
579462306a36Sopenharmony_ci
579562306a36Sopenharmony_ci	rtl8152_apply_firmware(tp, false);
579662306a36Sopenharmony_ci
579762306a36Sopenharmony_ci	if (tp->version == RTL_VER_03) {
579862306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_EEE_CFG);
579962306a36Sopenharmony_ci		data &= ~CTAP_SHORT_EN;
580062306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_EEE_CFG, data);
580162306a36Sopenharmony_ci	}
580262306a36Sopenharmony_ci
580362306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_POWER_CFG);
580462306a36Sopenharmony_ci	data |= EEE_CLKDIV_EN;
580562306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_POWER_CFG, data);
580662306a36Sopenharmony_ci
580762306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_DOWN_SPEED);
580862306a36Sopenharmony_ci	data |= EN_10M_BGOFF;
580962306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_DOWN_SPEED, data);
581062306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_POWER_CFG);
581162306a36Sopenharmony_ci	data |= EN_10M_PLLOFF;
581262306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_POWER_CFG, data);
581362306a36Sopenharmony_ci	sram_write(tp, SRAM_IMPEDANCE, 0x0b13);
581462306a36Sopenharmony_ci
581562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
581662306a36Sopenharmony_ci	ocp_data |= PFM_PWM_SWITCH;
581762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
581862306a36Sopenharmony_ci
581962306a36Sopenharmony_ci	/* Enable LPF corner auto tune */
582062306a36Sopenharmony_ci	sram_write(tp, SRAM_LPF_CFG, 0xf70f);
582162306a36Sopenharmony_ci
582262306a36Sopenharmony_ci	/* Adjust 10M Amplitude */
582362306a36Sopenharmony_ci	sram_write(tp, SRAM_10M_AMP1, 0x00af);
582462306a36Sopenharmony_ci	sram_write(tp, SRAM_10M_AMP2, 0x0208);
582562306a36Sopenharmony_ci
582662306a36Sopenharmony_ci	if (tp->eee_en)
582762306a36Sopenharmony_ci		rtl_eee_enable(tp, true);
582862306a36Sopenharmony_ci
582962306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
583062306a36Sopenharmony_ci	r8152b_enable_fc(tp);
583162306a36Sopenharmony_ci
583262306a36Sopenharmony_ci	switch (tp->version) {
583362306a36Sopenharmony_ci	case RTL_VER_03:
583462306a36Sopenharmony_ci	case RTL_VER_04:
583562306a36Sopenharmony_ci		break;
583662306a36Sopenharmony_ci	case RTL_VER_05:
583762306a36Sopenharmony_ci	case RTL_VER_06:
583862306a36Sopenharmony_ci	default:
583962306a36Sopenharmony_ci		r8153_u2p3en(tp, true);
584062306a36Sopenharmony_ci		break;
584162306a36Sopenharmony_ci	}
584262306a36Sopenharmony_ci
584362306a36Sopenharmony_ci	set_bit(PHY_RESET, &tp->flags);
584462306a36Sopenharmony_ci}
584562306a36Sopenharmony_ci
584662306a36Sopenharmony_cistatic u32 r8152_efuse_read(struct r8152 *tp, u8 addr)
584762306a36Sopenharmony_ci{
584862306a36Sopenharmony_ci	u32 ocp_data;
584962306a36Sopenharmony_ci
585062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD, EFUSE_READ_CMD | addr);
585162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD);
585262306a36Sopenharmony_ci	ocp_data = (ocp_data & EFUSE_DATA_BIT16) << 9;	/* data of bit16 */
585362306a36Sopenharmony_ci	ocp_data |= ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_DATA);
585462306a36Sopenharmony_ci
585562306a36Sopenharmony_ci	return ocp_data;
585662306a36Sopenharmony_ci}
585762306a36Sopenharmony_ci
585862306a36Sopenharmony_cistatic void r8153b_hw_phy_cfg(struct r8152 *tp)
585962306a36Sopenharmony_ci{
586062306a36Sopenharmony_ci	u32 ocp_data;
586162306a36Sopenharmony_ci	u16 data;
586262306a36Sopenharmony_ci
586362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
586462306a36Sopenharmony_ci	if (ocp_data & PCUT_STATUS) {
586562306a36Sopenharmony_ci		ocp_data &= ~PCUT_STATUS;
586662306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
586762306a36Sopenharmony_ci	}
586862306a36Sopenharmony_ci
586962306a36Sopenharmony_ci	/* disable ALDPS before updating the PHY parameters */
587062306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
587162306a36Sopenharmony_ci
587262306a36Sopenharmony_ci	/* disable EEE before updating the PHY parameters */
587362306a36Sopenharmony_ci	rtl_eee_enable(tp, false);
587462306a36Sopenharmony_ci
587562306a36Sopenharmony_ci	/* U1/U2/L1 idle timer. 500 us */
587662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
587762306a36Sopenharmony_ci
587862306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
587962306a36Sopenharmony_ci
588062306a36Sopenharmony_ci	switch (data) {
588162306a36Sopenharmony_ci	case PHY_STAT_PWRDN:
588262306a36Sopenharmony_ci	case PHY_STAT_EXT_INIT:
588362306a36Sopenharmony_ci		rtl8152_apply_firmware(tp, true);
588462306a36Sopenharmony_ci
588562306a36Sopenharmony_ci		data = r8152_mdio_read(tp, MII_BMCR);
588662306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
588762306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
588862306a36Sopenharmony_ci		break;
588962306a36Sopenharmony_ci	case PHY_STAT_LAN_ON:
589062306a36Sopenharmony_ci	default:
589162306a36Sopenharmony_ci		rtl8152_apply_firmware(tp, false);
589262306a36Sopenharmony_ci		break;
589362306a36Sopenharmony_ci	}
589462306a36Sopenharmony_ci
589562306a36Sopenharmony_ci	r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
589662306a36Sopenharmony_ci
589762306a36Sopenharmony_ci	data = sram_read(tp, SRAM_GREEN_CFG);
589862306a36Sopenharmony_ci	data |= R_TUNE_EN;
589962306a36Sopenharmony_ci	sram_write(tp, SRAM_GREEN_CFG, data);
590062306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_NCTL_CFG);
590162306a36Sopenharmony_ci	data |= PGA_RETURN_EN;
590262306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_NCTL_CFG, data);
590362306a36Sopenharmony_ci
590462306a36Sopenharmony_ci	/* ADC Bias Calibration:
590562306a36Sopenharmony_ci	 * read efuse offset 0x7d to get a 17-bit data. Remove the dummy/fake
590662306a36Sopenharmony_ci	 * bit (bit3) to rebuild the real 16-bit data. Write the data to the
590762306a36Sopenharmony_ci	 * ADC ioffset.
590862306a36Sopenharmony_ci	 */
590962306a36Sopenharmony_ci	ocp_data = r8152_efuse_read(tp, 0x7d);
591062306a36Sopenharmony_ci	data = (u16)(((ocp_data & 0x1fff0) >> 1) | (ocp_data & 0x7));
591162306a36Sopenharmony_ci	if (data != 0xffff)
591262306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_ADC_IOFFSET, data);
591362306a36Sopenharmony_ci
591462306a36Sopenharmony_ci	/* ups mode tx-link-pulse timing adjustment:
591562306a36Sopenharmony_ci	 * rg_saw_cnt = OCP reg 0xC426 Bit[13:0]
591662306a36Sopenharmony_ci	 * swr_cnt_1ms_ini = 16000000 / rg_saw_cnt
591762306a36Sopenharmony_ci	 */
591862306a36Sopenharmony_ci	ocp_data = ocp_reg_read(tp, 0xc426);
591962306a36Sopenharmony_ci	ocp_data &= 0x3fff;
592062306a36Sopenharmony_ci	if (ocp_data) {
592162306a36Sopenharmony_ci		u32 swr_cnt_1ms_ini;
592262306a36Sopenharmony_ci
592362306a36Sopenharmony_ci		swr_cnt_1ms_ini = (16000000 / ocp_data) & SAW_CNT_1MS_MASK;
592462306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG);
592562306a36Sopenharmony_ci		ocp_data = (ocp_data & ~SAW_CNT_1MS_MASK) | swr_cnt_1ms_ini;
592662306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CFG, ocp_data);
592762306a36Sopenharmony_ci	}
592862306a36Sopenharmony_ci
592962306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
593062306a36Sopenharmony_ci	ocp_data |= PFM_PWM_SWITCH;
593162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
593262306a36Sopenharmony_ci
593362306a36Sopenharmony_ci	/* Advnace EEE */
593462306a36Sopenharmony_ci	if (!rtl_phy_patch_request(tp, true, true)) {
593562306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_POWER_CFG);
593662306a36Sopenharmony_ci		data |= EEE_CLKDIV_EN;
593762306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_POWER_CFG, data);
593862306a36Sopenharmony_ci		tp->ups_info.eee_ckdiv = true;
593962306a36Sopenharmony_ci
594062306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_DOWN_SPEED);
594162306a36Sopenharmony_ci		data |= EN_EEE_CMODE | EN_EEE_1000 | EN_10M_CLKDIV;
594262306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_DOWN_SPEED, data);
594362306a36Sopenharmony_ci		tp->ups_info.eee_cmod_lv = true;
594462306a36Sopenharmony_ci		tp->ups_info._10m_ckdiv = true;
594562306a36Sopenharmony_ci		tp->ups_info.eee_plloff_giga = true;
594662306a36Sopenharmony_ci
594762306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_SYSCLK_CFG, 0);
594862306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_SYSCLK_CFG, clk_div_expo(5));
594962306a36Sopenharmony_ci		tp->ups_info._250m_ckdiv = true;
595062306a36Sopenharmony_ci
595162306a36Sopenharmony_ci		rtl_phy_patch_request(tp, false, true);
595262306a36Sopenharmony_ci	}
595362306a36Sopenharmony_ci
595462306a36Sopenharmony_ci	if (tp->eee_en)
595562306a36Sopenharmony_ci		rtl_eee_enable(tp, true);
595662306a36Sopenharmony_ci
595762306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
595862306a36Sopenharmony_ci	r8152b_enable_fc(tp);
595962306a36Sopenharmony_ci
596062306a36Sopenharmony_ci	set_bit(PHY_RESET, &tp->flags);
596162306a36Sopenharmony_ci}
596262306a36Sopenharmony_ci
596362306a36Sopenharmony_cistatic void r8153c_hw_phy_cfg(struct r8152 *tp)
596462306a36Sopenharmony_ci{
596562306a36Sopenharmony_ci	r8153b_hw_phy_cfg(tp);
596662306a36Sopenharmony_ci
596762306a36Sopenharmony_ci	tp->ups_info.r_tune = true;
596862306a36Sopenharmony_ci}
596962306a36Sopenharmony_ci
597062306a36Sopenharmony_cistatic void rtl8153_change_mtu(struct r8152 *tp)
597162306a36Sopenharmony_ci{
597262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
597362306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
597462306a36Sopenharmony_ci}
597562306a36Sopenharmony_ci
597662306a36Sopenharmony_cistatic void r8153_first_init(struct r8152 *tp)
597762306a36Sopenharmony_ci{
597862306a36Sopenharmony_ci	u32 ocp_data;
597962306a36Sopenharmony_ci
598062306a36Sopenharmony_ci	rxdy_gated_en(tp, true);
598162306a36Sopenharmony_ci	r8153_teredo_off(tp);
598262306a36Sopenharmony_ci
598362306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
598462306a36Sopenharmony_ci	ocp_data &= ~RCR_ACPT_ALL;
598562306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
598662306a36Sopenharmony_ci
598762306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
598862306a36Sopenharmony_ci	rtl_reset_bmu(tp);
598962306a36Sopenharmony_ci
599062306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
599162306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
599262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
599362306a36Sopenharmony_ci
599462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
599562306a36Sopenharmony_ci	ocp_data &= ~MCU_BORW_EN;
599662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
599762306a36Sopenharmony_ci
599862306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
599962306a36Sopenharmony_ci
600062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
600162306a36Sopenharmony_ci	ocp_data |= RE_INIT_LL;
600262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
600362306a36Sopenharmony_ci
600462306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
600562306a36Sopenharmony_ci
600662306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
600762306a36Sopenharmony_ci
600862306a36Sopenharmony_ci	rtl8153_change_mtu(tp);
600962306a36Sopenharmony_ci
601062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
601162306a36Sopenharmony_ci	ocp_data |= TCR0_AUTO_FIFO;
601262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
601362306a36Sopenharmony_ci
601462306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
601562306a36Sopenharmony_ci
601662306a36Sopenharmony_ci	/* rx share fifo credit full threshold */
601762306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
601862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL);
601962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);
602062306a36Sopenharmony_ci	/* TX share fifo free credit full threshold */
602162306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
602262306a36Sopenharmony_ci}
602362306a36Sopenharmony_ci
602462306a36Sopenharmony_cistatic void r8153_enter_oob(struct r8152 *tp)
602562306a36Sopenharmony_ci{
602662306a36Sopenharmony_ci	u32 ocp_data;
602762306a36Sopenharmony_ci
602862306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
602962306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
603062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
603162306a36Sopenharmony_ci
603262306a36Sopenharmony_ci	/* RX FIFO settings for OOB */
603362306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
603462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
603562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
603662306a36Sopenharmony_ci
603762306a36Sopenharmony_ci	rtl_disable(tp);
603862306a36Sopenharmony_ci	rtl_reset_bmu(tp);
603962306a36Sopenharmony_ci
604062306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
604162306a36Sopenharmony_ci
604262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
604362306a36Sopenharmony_ci	ocp_data |= RE_INIT_LL;
604462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
604562306a36Sopenharmony_ci
604662306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
604762306a36Sopenharmony_ci
604862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
604962306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
605062306a36Sopenharmony_ci
605162306a36Sopenharmony_ci	switch (tp->version) {
605262306a36Sopenharmony_ci	case RTL_VER_03:
605362306a36Sopenharmony_ci	case RTL_VER_04:
605462306a36Sopenharmony_ci	case RTL_VER_05:
605562306a36Sopenharmony_ci	case RTL_VER_06:
605662306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
605762306a36Sopenharmony_ci		ocp_data &= ~TEREDO_WAKE_MASK;
605862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
605962306a36Sopenharmony_ci		break;
606062306a36Sopenharmony_ci
606162306a36Sopenharmony_ci	case RTL_VER_08:
606262306a36Sopenharmony_ci	case RTL_VER_09:
606362306a36Sopenharmony_ci	case RTL_VER_14:
606462306a36Sopenharmony_ci		/* Clear teredo wake event. bit[15:8] is the teredo wakeup
606562306a36Sopenharmony_ci		 * type. Set it to zero. bits[7:0] are the W1C bits about
606662306a36Sopenharmony_ci		 * the events. Set them to all 1 to clear them.
606762306a36Sopenharmony_ci		 */
606862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff);
606962306a36Sopenharmony_ci		break;
607062306a36Sopenharmony_ci
607162306a36Sopenharmony_ci	default:
607262306a36Sopenharmony_ci		break;
607362306a36Sopenharmony_ci	}
607462306a36Sopenharmony_ci
607562306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, true);
607662306a36Sopenharmony_ci
607762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
607862306a36Sopenharmony_ci	ocp_data |= ALDPS_PROXY_MODE;
607962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
608062306a36Sopenharmony_ci
608162306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
608262306a36Sopenharmony_ci	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
608362306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
608462306a36Sopenharmony_ci
608562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
608662306a36Sopenharmony_ci	ocp_data |= MCU_BORW_EN;
608762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
608862306a36Sopenharmony_ci
608962306a36Sopenharmony_ci	rxdy_gated_en(tp, false);
609062306a36Sopenharmony_ci
609162306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
609262306a36Sopenharmony_ci	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
609362306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
609462306a36Sopenharmony_ci}
609562306a36Sopenharmony_ci
609662306a36Sopenharmony_cistatic void rtl8153_disable(struct r8152 *tp)
609762306a36Sopenharmony_ci{
609862306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
609962306a36Sopenharmony_ci	rtl_disable(tp);
610062306a36Sopenharmony_ci	rtl_reset_bmu(tp);
610162306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
610262306a36Sopenharmony_ci}
610362306a36Sopenharmony_ci
610462306a36Sopenharmony_cistatic u32 fc_pause_on_auto(struct r8152 *tp)
610562306a36Sopenharmony_ci{
610662306a36Sopenharmony_ci	return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 6 * 1024);
610762306a36Sopenharmony_ci}
610862306a36Sopenharmony_ci
610962306a36Sopenharmony_cistatic u32 fc_pause_off_auto(struct r8152 *tp)
611062306a36Sopenharmony_ci{
611162306a36Sopenharmony_ci	return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 14 * 1024);
611262306a36Sopenharmony_ci}
611362306a36Sopenharmony_ci
611462306a36Sopenharmony_cistatic void r8156_fc_parameter(struct r8152 *tp)
611562306a36Sopenharmony_ci{
611662306a36Sopenharmony_ci	u32 pause_on = tp->fc_pause_on ? tp->fc_pause_on : fc_pause_on_auto(tp);
611762306a36Sopenharmony_ci	u32 pause_off = tp->fc_pause_off ? tp->fc_pause_off : fc_pause_off_auto(tp);
611862306a36Sopenharmony_ci
611962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 16);
612062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16);
612162306a36Sopenharmony_ci}
612262306a36Sopenharmony_ci
612362306a36Sopenharmony_cistatic int rtl8156_enable(struct r8152 *tp)
612462306a36Sopenharmony_ci{
612562306a36Sopenharmony_ci	u32 ocp_data;
612662306a36Sopenharmony_ci	u16 speed;
612762306a36Sopenharmony_ci
612862306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
612962306a36Sopenharmony_ci		return -ENODEV;
613062306a36Sopenharmony_ci
613162306a36Sopenharmony_ci	r8156_fc_parameter(tp);
613262306a36Sopenharmony_ci	set_tx_qlen(tp);
613362306a36Sopenharmony_ci	rtl_set_eee_plus(tp);
613462306a36Sopenharmony_ci	r8153_set_rx_early_timeout(tp);
613562306a36Sopenharmony_ci	r8153_set_rx_early_size(tp);
613662306a36Sopenharmony_ci
613762306a36Sopenharmony_ci	speed = rtl8152_get_speed(tp);
613862306a36Sopenharmony_ci	rtl_set_ifg(tp, speed);
613962306a36Sopenharmony_ci
614062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
614162306a36Sopenharmony_ci	if (speed & _2500bps)
614262306a36Sopenharmony_ci		ocp_data &= ~IDLE_SPDWN_EN;
614362306a36Sopenharmony_ci	else
614462306a36Sopenharmony_ci		ocp_data |= IDLE_SPDWN_EN;
614562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
614662306a36Sopenharmony_ci
614762306a36Sopenharmony_ci	if (speed & _1000bps)
614862306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x11);
614962306a36Sopenharmony_ci	else if (speed & _500bps)
615062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x3d);
615162306a36Sopenharmony_ci
615262306a36Sopenharmony_ci	if (tp->udev->speed == USB_SPEED_HIGH) {
615362306a36Sopenharmony_ci		/* USB 0xb45e[3:0] l1_nyet_hird */
615462306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_L1_CTRL);
615562306a36Sopenharmony_ci		ocp_data &= ~0xf;
615662306a36Sopenharmony_ci		if (is_flow_control(speed))
615762306a36Sopenharmony_ci			ocp_data |= 0xf;
615862306a36Sopenharmony_ci		else
615962306a36Sopenharmony_ci			ocp_data |= 0x1;
616062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_L1_CTRL, ocp_data);
616162306a36Sopenharmony_ci	}
616262306a36Sopenharmony_ci
616362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
616462306a36Sopenharmony_ci	ocp_data &= ~FC_PATCH_TASK;
616562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
616662306a36Sopenharmony_ci	usleep_range(1000, 2000);
616762306a36Sopenharmony_ci	ocp_data |= FC_PATCH_TASK;
616862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
616962306a36Sopenharmony_ci
617062306a36Sopenharmony_ci	return rtl_enable(tp);
617162306a36Sopenharmony_ci}
617262306a36Sopenharmony_ci
617362306a36Sopenharmony_cistatic void rtl8156_disable(struct r8152 *tp)
617462306a36Sopenharmony_ci{
617562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, 0);
617662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, 0);
617762306a36Sopenharmony_ci
617862306a36Sopenharmony_ci	rtl8153_disable(tp);
617962306a36Sopenharmony_ci}
618062306a36Sopenharmony_ci
618162306a36Sopenharmony_cistatic int rtl8156b_enable(struct r8152 *tp)
618262306a36Sopenharmony_ci{
618362306a36Sopenharmony_ci	u32 ocp_data;
618462306a36Sopenharmony_ci	u16 speed;
618562306a36Sopenharmony_ci
618662306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
618762306a36Sopenharmony_ci		return -ENODEV;
618862306a36Sopenharmony_ci
618962306a36Sopenharmony_ci	set_tx_qlen(tp);
619062306a36Sopenharmony_ci	rtl_set_eee_plus(tp);
619162306a36Sopenharmony_ci
619262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM);
619362306a36Sopenharmony_ci	ocp_data &= ~RX_AGGR_NUM_MASK;
619462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM, ocp_data);
619562306a36Sopenharmony_ci
619662306a36Sopenharmony_ci	r8153_set_rx_early_timeout(tp);
619762306a36Sopenharmony_ci	r8153_set_rx_early_size(tp);
619862306a36Sopenharmony_ci
619962306a36Sopenharmony_ci	speed = rtl8152_get_speed(tp);
620062306a36Sopenharmony_ci	rtl_set_ifg(tp, speed);
620162306a36Sopenharmony_ci
620262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
620362306a36Sopenharmony_ci	if (speed & _2500bps)
620462306a36Sopenharmony_ci		ocp_data &= ~IDLE_SPDWN_EN;
620562306a36Sopenharmony_ci	else
620662306a36Sopenharmony_ci		ocp_data |= IDLE_SPDWN_EN;
620762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
620862306a36Sopenharmony_ci
620962306a36Sopenharmony_ci	if (tp->udev->speed == USB_SPEED_HIGH) {
621062306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_L1_CTRL);
621162306a36Sopenharmony_ci		ocp_data &= ~0xf;
621262306a36Sopenharmony_ci		if (is_flow_control(speed))
621362306a36Sopenharmony_ci			ocp_data |= 0xf;
621462306a36Sopenharmony_ci		else
621562306a36Sopenharmony_ci			ocp_data |= 0x1;
621662306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_L1_CTRL, ocp_data);
621762306a36Sopenharmony_ci	}
621862306a36Sopenharmony_ci
621962306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
622062306a36Sopenharmony_ci	ocp_data &= ~FC_PATCH_TASK;
622162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
622262306a36Sopenharmony_ci	usleep_range(1000, 2000);
622362306a36Sopenharmony_ci	ocp_data |= FC_PATCH_TASK;
622462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
622562306a36Sopenharmony_ci
622662306a36Sopenharmony_ci	return rtl_enable(tp);
622762306a36Sopenharmony_ci}
622862306a36Sopenharmony_ci
622962306a36Sopenharmony_cistatic int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
623062306a36Sopenharmony_ci			     u32 advertising)
623162306a36Sopenharmony_ci{
623262306a36Sopenharmony_ci	u16 bmcr;
623362306a36Sopenharmony_ci	int ret = 0;
623462306a36Sopenharmony_ci
623562306a36Sopenharmony_ci	if (autoneg == AUTONEG_DISABLE) {
623662306a36Sopenharmony_ci		if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL)
623762306a36Sopenharmony_ci			return -EINVAL;
623862306a36Sopenharmony_ci
623962306a36Sopenharmony_ci		switch (speed) {
624062306a36Sopenharmony_ci		case SPEED_10:
624162306a36Sopenharmony_ci			bmcr = BMCR_SPEED10;
624262306a36Sopenharmony_ci			if (duplex == DUPLEX_FULL) {
624362306a36Sopenharmony_ci				bmcr |= BMCR_FULLDPLX;
624462306a36Sopenharmony_ci				tp->ups_info.speed_duplex = FORCE_10M_FULL;
624562306a36Sopenharmony_ci			} else {
624662306a36Sopenharmony_ci				tp->ups_info.speed_duplex = FORCE_10M_HALF;
624762306a36Sopenharmony_ci			}
624862306a36Sopenharmony_ci			break;
624962306a36Sopenharmony_ci		case SPEED_100:
625062306a36Sopenharmony_ci			bmcr = BMCR_SPEED100;
625162306a36Sopenharmony_ci			if (duplex == DUPLEX_FULL) {
625262306a36Sopenharmony_ci				bmcr |= BMCR_FULLDPLX;
625362306a36Sopenharmony_ci				tp->ups_info.speed_duplex = FORCE_100M_FULL;
625462306a36Sopenharmony_ci			} else {
625562306a36Sopenharmony_ci				tp->ups_info.speed_duplex = FORCE_100M_HALF;
625662306a36Sopenharmony_ci			}
625762306a36Sopenharmony_ci			break;
625862306a36Sopenharmony_ci		case SPEED_1000:
625962306a36Sopenharmony_ci			if (tp->mii.supports_gmii) {
626062306a36Sopenharmony_ci				bmcr = BMCR_SPEED1000 | BMCR_FULLDPLX;
626162306a36Sopenharmony_ci				tp->ups_info.speed_duplex = NWAY_1000M_FULL;
626262306a36Sopenharmony_ci				break;
626362306a36Sopenharmony_ci			}
626462306a36Sopenharmony_ci			fallthrough;
626562306a36Sopenharmony_ci		default:
626662306a36Sopenharmony_ci			ret = -EINVAL;
626762306a36Sopenharmony_ci			goto out;
626862306a36Sopenharmony_ci		}
626962306a36Sopenharmony_ci
627062306a36Sopenharmony_ci		if (duplex == DUPLEX_FULL)
627162306a36Sopenharmony_ci			tp->mii.full_duplex = 1;
627262306a36Sopenharmony_ci		else
627362306a36Sopenharmony_ci			tp->mii.full_duplex = 0;
627462306a36Sopenharmony_ci
627562306a36Sopenharmony_ci		tp->mii.force_media = 1;
627662306a36Sopenharmony_ci	} else {
627762306a36Sopenharmony_ci		u16 orig, new1;
627862306a36Sopenharmony_ci		u32 support;
627962306a36Sopenharmony_ci
628062306a36Sopenharmony_ci		support = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
628162306a36Sopenharmony_ci			  RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
628262306a36Sopenharmony_ci
628362306a36Sopenharmony_ci		if (tp->mii.supports_gmii) {
628462306a36Sopenharmony_ci			support |= RTL_ADVERTISED_1000_FULL;
628562306a36Sopenharmony_ci
628662306a36Sopenharmony_ci			if (tp->support_2500full)
628762306a36Sopenharmony_ci				support |= RTL_ADVERTISED_2500_FULL;
628862306a36Sopenharmony_ci		}
628962306a36Sopenharmony_ci
629062306a36Sopenharmony_ci		if (!(advertising & support))
629162306a36Sopenharmony_ci			return -EINVAL;
629262306a36Sopenharmony_ci
629362306a36Sopenharmony_ci		orig = r8152_mdio_read(tp, MII_ADVERTISE);
629462306a36Sopenharmony_ci		new1 = orig & ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
629562306a36Sopenharmony_ci				ADVERTISE_100HALF | ADVERTISE_100FULL);
629662306a36Sopenharmony_ci		if (advertising & RTL_ADVERTISED_10_HALF) {
629762306a36Sopenharmony_ci			new1 |= ADVERTISE_10HALF;
629862306a36Sopenharmony_ci			tp->ups_info.speed_duplex = NWAY_10M_HALF;
629962306a36Sopenharmony_ci		}
630062306a36Sopenharmony_ci		if (advertising & RTL_ADVERTISED_10_FULL) {
630162306a36Sopenharmony_ci			new1 |= ADVERTISE_10FULL;
630262306a36Sopenharmony_ci			tp->ups_info.speed_duplex = NWAY_10M_FULL;
630362306a36Sopenharmony_ci		}
630462306a36Sopenharmony_ci
630562306a36Sopenharmony_ci		if (advertising & RTL_ADVERTISED_100_HALF) {
630662306a36Sopenharmony_ci			new1 |= ADVERTISE_100HALF;
630762306a36Sopenharmony_ci			tp->ups_info.speed_duplex = NWAY_100M_HALF;
630862306a36Sopenharmony_ci		}
630962306a36Sopenharmony_ci		if (advertising & RTL_ADVERTISED_100_FULL) {
631062306a36Sopenharmony_ci			new1 |= ADVERTISE_100FULL;
631162306a36Sopenharmony_ci			tp->ups_info.speed_duplex = NWAY_100M_FULL;
631262306a36Sopenharmony_ci		}
631362306a36Sopenharmony_ci
631462306a36Sopenharmony_ci		if (orig != new1) {
631562306a36Sopenharmony_ci			r8152_mdio_write(tp, MII_ADVERTISE, new1);
631662306a36Sopenharmony_ci			tp->mii.advertising = new1;
631762306a36Sopenharmony_ci		}
631862306a36Sopenharmony_ci
631962306a36Sopenharmony_ci		if (tp->mii.supports_gmii) {
632062306a36Sopenharmony_ci			orig = r8152_mdio_read(tp, MII_CTRL1000);
632162306a36Sopenharmony_ci			new1 = orig & ~(ADVERTISE_1000FULL |
632262306a36Sopenharmony_ci					ADVERTISE_1000HALF);
632362306a36Sopenharmony_ci
632462306a36Sopenharmony_ci			if (advertising & RTL_ADVERTISED_1000_FULL) {
632562306a36Sopenharmony_ci				new1 |= ADVERTISE_1000FULL;
632662306a36Sopenharmony_ci				tp->ups_info.speed_duplex = NWAY_1000M_FULL;
632762306a36Sopenharmony_ci			}
632862306a36Sopenharmony_ci
632962306a36Sopenharmony_ci			if (orig != new1)
633062306a36Sopenharmony_ci				r8152_mdio_write(tp, MII_CTRL1000, new1);
633162306a36Sopenharmony_ci		}
633262306a36Sopenharmony_ci
633362306a36Sopenharmony_ci		if (tp->support_2500full) {
633462306a36Sopenharmony_ci			orig = ocp_reg_read(tp, OCP_10GBT_CTRL);
633562306a36Sopenharmony_ci			new1 = orig & ~MDIO_AN_10GBT_CTRL_ADV2_5G;
633662306a36Sopenharmony_ci
633762306a36Sopenharmony_ci			if (advertising & RTL_ADVERTISED_2500_FULL) {
633862306a36Sopenharmony_ci				new1 |= MDIO_AN_10GBT_CTRL_ADV2_5G;
633962306a36Sopenharmony_ci				tp->ups_info.speed_duplex = NWAY_2500M_FULL;
634062306a36Sopenharmony_ci			}
634162306a36Sopenharmony_ci
634262306a36Sopenharmony_ci			if (orig != new1)
634362306a36Sopenharmony_ci				ocp_reg_write(tp, OCP_10GBT_CTRL, new1);
634462306a36Sopenharmony_ci		}
634562306a36Sopenharmony_ci
634662306a36Sopenharmony_ci		bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
634762306a36Sopenharmony_ci
634862306a36Sopenharmony_ci		tp->mii.force_media = 0;
634962306a36Sopenharmony_ci	}
635062306a36Sopenharmony_ci
635162306a36Sopenharmony_ci	if (test_and_clear_bit(PHY_RESET, &tp->flags))
635262306a36Sopenharmony_ci		bmcr |= BMCR_RESET;
635362306a36Sopenharmony_ci
635462306a36Sopenharmony_ci	r8152_mdio_write(tp, MII_BMCR, bmcr);
635562306a36Sopenharmony_ci
635662306a36Sopenharmony_ci	if (bmcr & BMCR_RESET) {
635762306a36Sopenharmony_ci		int i;
635862306a36Sopenharmony_ci
635962306a36Sopenharmony_ci		for (i = 0; i < 50; i++) {
636062306a36Sopenharmony_ci			msleep(20);
636162306a36Sopenharmony_ci			if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
636262306a36Sopenharmony_ci				break;
636362306a36Sopenharmony_ci		}
636462306a36Sopenharmony_ci	}
636562306a36Sopenharmony_ci
636662306a36Sopenharmony_ciout:
636762306a36Sopenharmony_ci	return ret;
636862306a36Sopenharmony_ci}
636962306a36Sopenharmony_ci
637062306a36Sopenharmony_cistatic void rtl8152_up(struct r8152 *tp)
637162306a36Sopenharmony_ci{
637262306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
637362306a36Sopenharmony_ci		return;
637462306a36Sopenharmony_ci
637562306a36Sopenharmony_ci	r8152_aldps_en(tp, false);
637662306a36Sopenharmony_ci	r8152b_exit_oob(tp);
637762306a36Sopenharmony_ci	r8152_aldps_en(tp, true);
637862306a36Sopenharmony_ci}
637962306a36Sopenharmony_ci
638062306a36Sopenharmony_cistatic void rtl8152_down(struct r8152 *tp)
638162306a36Sopenharmony_ci{
638262306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
638362306a36Sopenharmony_ci		rtl_drop_queued_tx(tp);
638462306a36Sopenharmony_ci		return;
638562306a36Sopenharmony_ci	}
638662306a36Sopenharmony_ci
638762306a36Sopenharmony_ci	r8152_power_cut_en(tp, false);
638862306a36Sopenharmony_ci	r8152_aldps_en(tp, false);
638962306a36Sopenharmony_ci	r8152b_enter_oob(tp);
639062306a36Sopenharmony_ci	r8152_aldps_en(tp, true);
639162306a36Sopenharmony_ci}
639262306a36Sopenharmony_ci
639362306a36Sopenharmony_cistatic void rtl8153_up(struct r8152 *tp)
639462306a36Sopenharmony_ci{
639562306a36Sopenharmony_ci	u32 ocp_data;
639662306a36Sopenharmony_ci
639762306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
639862306a36Sopenharmony_ci		return;
639962306a36Sopenharmony_ci
640062306a36Sopenharmony_ci	r8153_u1u2en(tp, false);
640162306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
640262306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
640362306a36Sopenharmony_ci	r8153_first_init(tp);
640462306a36Sopenharmony_ci
640562306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
640662306a36Sopenharmony_ci	ocp_data |= LANWAKE_CLR_EN;
640762306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data);
640862306a36Sopenharmony_ci
640962306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG);
641062306a36Sopenharmony_ci	ocp_data &= ~LANWAKE_PIN;
641162306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data);
641262306a36Sopenharmony_ci
641362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK1);
641462306a36Sopenharmony_ci	ocp_data &= ~DELAY_PHY_PWR_CHG;
641562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK1, ocp_data);
641662306a36Sopenharmony_ci
641762306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
641862306a36Sopenharmony_ci
641962306a36Sopenharmony_ci	switch (tp->version) {
642062306a36Sopenharmony_ci	case RTL_VER_03:
642162306a36Sopenharmony_ci	case RTL_VER_04:
642262306a36Sopenharmony_ci		break;
642362306a36Sopenharmony_ci	case RTL_VER_05:
642462306a36Sopenharmony_ci	case RTL_VER_06:
642562306a36Sopenharmony_ci	default:
642662306a36Sopenharmony_ci		r8153_u2p3en(tp, true);
642762306a36Sopenharmony_ci		break;
642862306a36Sopenharmony_ci	}
642962306a36Sopenharmony_ci
643062306a36Sopenharmony_ci	r8153_u1u2en(tp, true);
643162306a36Sopenharmony_ci}
643262306a36Sopenharmony_ci
643362306a36Sopenharmony_cistatic void rtl8153_down(struct r8152 *tp)
643462306a36Sopenharmony_ci{
643562306a36Sopenharmony_ci	u32 ocp_data;
643662306a36Sopenharmony_ci
643762306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
643862306a36Sopenharmony_ci		rtl_drop_queued_tx(tp);
643962306a36Sopenharmony_ci		return;
644062306a36Sopenharmony_ci	}
644162306a36Sopenharmony_ci
644262306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
644362306a36Sopenharmony_ci	ocp_data &= ~LANWAKE_CLR_EN;
644462306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data);
644562306a36Sopenharmony_ci
644662306a36Sopenharmony_ci	r8153_u1u2en(tp, false);
644762306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
644862306a36Sopenharmony_ci	r8153_power_cut_en(tp, false);
644962306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
645062306a36Sopenharmony_ci	r8153_enter_oob(tp);
645162306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
645262306a36Sopenharmony_ci}
645362306a36Sopenharmony_ci
645462306a36Sopenharmony_cistatic void rtl8153b_up(struct r8152 *tp)
645562306a36Sopenharmony_ci{
645662306a36Sopenharmony_ci	u32 ocp_data;
645762306a36Sopenharmony_ci
645862306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
645962306a36Sopenharmony_ci		return;
646062306a36Sopenharmony_ci
646162306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
646262306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
646362306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
646462306a36Sopenharmony_ci
646562306a36Sopenharmony_ci	r8153_first_init(tp);
646662306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B);
646762306a36Sopenharmony_ci
646862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
646962306a36Sopenharmony_ci	ocp_data &= ~PLA_MCU_SPDWN_EN;
647062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
647162306a36Sopenharmony_ci
647262306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
647362306a36Sopenharmony_ci
647462306a36Sopenharmony_ci	if (tp->udev->speed >= USB_SPEED_SUPER)
647562306a36Sopenharmony_ci		r8153b_u1u2en(tp, true);
647662306a36Sopenharmony_ci}
647762306a36Sopenharmony_ci
647862306a36Sopenharmony_cistatic void rtl8153b_down(struct r8152 *tp)
647962306a36Sopenharmony_ci{
648062306a36Sopenharmony_ci	u32 ocp_data;
648162306a36Sopenharmony_ci
648262306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
648362306a36Sopenharmony_ci		rtl_drop_queued_tx(tp);
648462306a36Sopenharmony_ci		return;
648562306a36Sopenharmony_ci	}
648662306a36Sopenharmony_ci
648762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
648862306a36Sopenharmony_ci	ocp_data |= PLA_MCU_SPDWN_EN;
648962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
649062306a36Sopenharmony_ci
649162306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
649262306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
649362306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
649462306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
649562306a36Sopenharmony_ci	r8153_enter_oob(tp);
649662306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
649762306a36Sopenharmony_ci}
649862306a36Sopenharmony_ci
649962306a36Sopenharmony_cistatic void rtl8153c_change_mtu(struct r8152 *tp)
650062306a36Sopenharmony_ci{
650162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
650262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, 10 * 1024 / 64);
650362306a36Sopenharmony_ci
650462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
650562306a36Sopenharmony_ci
650662306a36Sopenharmony_ci	/* Adjust the tx fifo free credit full threshold, otherwise
650762306a36Sopenharmony_ci	 * the fifo would be too small to send a jumbo frame packet.
650862306a36Sopenharmony_ci	 */
650962306a36Sopenharmony_ci	if (tp->netdev->mtu < 8000)
651062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL, 2048 / 8);
651162306a36Sopenharmony_ci	else
651262306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL, 900 / 8);
651362306a36Sopenharmony_ci}
651462306a36Sopenharmony_ci
651562306a36Sopenharmony_cistatic void rtl8153c_up(struct r8152 *tp)
651662306a36Sopenharmony_ci{
651762306a36Sopenharmony_ci	u32 ocp_data;
651862306a36Sopenharmony_ci
651962306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
652062306a36Sopenharmony_ci		return;
652162306a36Sopenharmony_ci
652262306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
652362306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
652462306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
652562306a36Sopenharmony_ci
652662306a36Sopenharmony_ci	rxdy_gated_en(tp, true);
652762306a36Sopenharmony_ci	r8153_teredo_off(tp);
652862306a36Sopenharmony_ci
652962306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
653062306a36Sopenharmony_ci	ocp_data &= ~RCR_ACPT_ALL;
653162306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
653262306a36Sopenharmony_ci
653362306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
653462306a36Sopenharmony_ci	rtl_reset_bmu(tp);
653562306a36Sopenharmony_ci
653662306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
653762306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
653862306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
653962306a36Sopenharmony_ci
654062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
654162306a36Sopenharmony_ci	ocp_data &= ~MCU_BORW_EN;
654262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
654362306a36Sopenharmony_ci
654462306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
654562306a36Sopenharmony_ci
654662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
654762306a36Sopenharmony_ci	ocp_data |= RE_INIT_LL;
654862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
654962306a36Sopenharmony_ci
655062306a36Sopenharmony_ci	wait_oob_link_list_ready(tp);
655162306a36Sopenharmony_ci
655262306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
655362306a36Sopenharmony_ci
655462306a36Sopenharmony_ci	rtl8153c_change_mtu(tp);
655562306a36Sopenharmony_ci
655662306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
655762306a36Sopenharmony_ci
655862306a36Sopenharmony_ci	/* rx share fifo credit full threshold */
655962306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, 0x02);
656062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, 0x08);
656162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL);
656262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);
656362306a36Sopenharmony_ci
656462306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B);
656562306a36Sopenharmony_ci
656662306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
656762306a36Sopenharmony_ci
656862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
656962306a36Sopenharmony_ci	ocp_data |= BIT(8);
657062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
657162306a36Sopenharmony_ci
657262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
657362306a36Sopenharmony_ci
657462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
657562306a36Sopenharmony_ci	ocp_data &= ~PLA_MCU_SPDWN_EN;
657662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
657762306a36Sopenharmony_ci
657862306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
657962306a36Sopenharmony_ci	r8153b_u1u2en(tp, true);
658062306a36Sopenharmony_ci}
658162306a36Sopenharmony_ci
658262306a36Sopenharmony_cistatic void rtl8156_change_mtu(struct r8152 *tp)
658362306a36Sopenharmony_ci{
658462306a36Sopenharmony_ci	u32 rx_max_size = mtu_to_size(tp->netdev->mtu);
658562306a36Sopenharmony_ci
658662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rx_max_size);
658762306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
658862306a36Sopenharmony_ci	r8156_fc_parameter(tp);
658962306a36Sopenharmony_ci
659062306a36Sopenharmony_ci	/* TX share fifo free credit full threshold */
659162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
659262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL,
659362306a36Sopenharmony_ci		       ALIGN(rx_max_size + sizeof(struct tx_desc), 1024) / 16);
659462306a36Sopenharmony_ci}
659562306a36Sopenharmony_ci
659662306a36Sopenharmony_cistatic void rtl8156_up(struct r8152 *tp)
659762306a36Sopenharmony_ci{
659862306a36Sopenharmony_ci	u32 ocp_data;
659962306a36Sopenharmony_ci
660062306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
660162306a36Sopenharmony_ci		return;
660262306a36Sopenharmony_ci
660362306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
660462306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
660562306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
660662306a36Sopenharmony_ci
660762306a36Sopenharmony_ci	rxdy_gated_en(tp, true);
660862306a36Sopenharmony_ci	r8153_teredo_off(tp);
660962306a36Sopenharmony_ci
661062306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
661162306a36Sopenharmony_ci	ocp_data &= ~RCR_ACPT_ALL;
661262306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
661362306a36Sopenharmony_ci
661462306a36Sopenharmony_ci	rtl8152_nic_reset(tp);
661562306a36Sopenharmony_ci	rtl_reset_bmu(tp);
661662306a36Sopenharmony_ci
661762306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
661862306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
661962306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
662062306a36Sopenharmony_ci
662162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
662262306a36Sopenharmony_ci	ocp_data &= ~MCU_BORW_EN;
662362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
662462306a36Sopenharmony_ci
662562306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
662662306a36Sopenharmony_ci
662762306a36Sopenharmony_ci	rtl8156_change_mtu(tp);
662862306a36Sopenharmony_ci
662962306a36Sopenharmony_ci	switch (tp->version) {
663062306a36Sopenharmony_ci	case RTL_TEST_01:
663162306a36Sopenharmony_ci	case RTL_VER_10:
663262306a36Sopenharmony_ci	case RTL_VER_11:
663362306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_CONFIG);
663462306a36Sopenharmony_ci		ocp_data |= ACT_ODMA;
663562306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ocp_data);
663662306a36Sopenharmony_ci		break;
663762306a36Sopenharmony_ci	default:
663862306a36Sopenharmony_ci		break;
663962306a36Sopenharmony_ci	}
664062306a36Sopenharmony_ci
664162306a36Sopenharmony_ci	/* share FIFO settings */
664262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL);
664362306a36Sopenharmony_ci	ocp_data &= ~RXFIFO_FULL_MASK;
664462306a36Sopenharmony_ci	ocp_data |= 0x08;
664562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, ocp_data);
664662306a36Sopenharmony_ci
664762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
664862306a36Sopenharmony_ci	ocp_data &= ~PLA_MCU_SPDWN_EN;
664962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
665062306a36Sopenharmony_ci
665162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION);
665262306a36Sopenharmony_ci	ocp_data &= ~(RG_PWRDN_EN | ALL_SPEED_OFF);
665362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, ocp_data);
665462306a36Sopenharmony_ci
665562306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, 0x00600400);
665662306a36Sopenharmony_ci
665762306a36Sopenharmony_ci	if (tp->saved_wolopts != __rtl_get_wol(tp)) {
665862306a36Sopenharmony_ci		netif_warn(tp, ifup, tp->netdev, "wol setting is changed\n");
665962306a36Sopenharmony_ci		__rtl_set_wol(tp, tp->saved_wolopts);
666062306a36Sopenharmony_ci	}
666162306a36Sopenharmony_ci
666262306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
666362306a36Sopenharmony_ci	r8153_u2p3en(tp, true);
666462306a36Sopenharmony_ci
666562306a36Sopenharmony_ci	if (tp->udev->speed >= USB_SPEED_SUPER)
666662306a36Sopenharmony_ci		r8153b_u1u2en(tp, true);
666762306a36Sopenharmony_ci}
666862306a36Sopenharmony_ci
666962306a36Sopenharmony_cistatic void rtl8156_down(struct r8152 *tp)
667062306a36Sopenharmony_ci{
667162306a36Sopenharmony_ci	u32 ocp_data;
667262306a36Sopenharmony_ci
667362306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
667462306a36Sopenharmony_ci		rtl_drop_queued_tx(tp);
667562306a36Sopenharmony_ci		return;
667662306a36Sopenharmony_ci	}
667762306a36Sopenharmony_ci
667862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
667962306a36Sopenharmony_ci	ocp_data |= PLA_MCU_SPDWN_EN;
668062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
668162306a36Sopenharmony_ci
668262306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
668362306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
668462306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
668562306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
668662306a36Sopenharmony_ci
668762306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
668862306a36Sopenharmony_ci	ocp_data &= ~NOW_IS_OOB;
668962306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
669062306a36Sopenharmony_ci
669162306a36Sopenharmony_ci	/* RX FIFO settings for OOB */
669262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, 64 / 16);
669362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, 1024 / 16);
669462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, 4096 / 16);
669562306a36Sopenharmony_ci
669662306a36Sopenharmony_ci	rtl_disable(tp);
669762306a36Sopenharmony_ci	rtl_reset_bmu(tp);
669862306a36Sopenharmony_ci
669962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
670062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
670162306a36Sopenharmony_ci
670262306a36Sopenharmony_ci	/* Clear teredo wake event. bit[15:8] is the teredo wakeup
670362306a36Sopenharmony_ci	 * type. Set it to zero. bits[7:0] are the W1C bits about
670462306a36Sopenharmony_ci	 * the events. Set them to all 1 to clear them.
670562306a36Sopenharmony_ci	 */
670662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff);
670762306a36Sopenharmony_ci
670862306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
670962306a36Sopenharmony_ci	ocp_data |= NOW_IS_OOB;
671062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
671162306a36Sopenharmony_ci
671262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
671362306a36Sopenharmony_ci	ocp_data |= MCU_BORW_EN;
671462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
671562306a36Sopenharmony_ci
671662306a36Sopenharmony_ci	rtl_rx_vlan_en(tp, true);
671762306a36Sopenharmony_ci	rxdy_gated_en(tp, false);
671862306a36Sopenharmony_ci
671962306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
672062306a36Sopenharmony_ci	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
672162306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
672262306a36Sopenharmony_ci
672362306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
672462306a36Sopenharmony_ci}
672562306a36Sopenharmony_ci
672662306a36Sopenharmony_cistatic bool rtl8152_in_nway(struct r8152 *tp)
672762306a36Sopenharmony_ci{
672862306a36Sopenharmony_ci	u16 nway_state;
672962306a36Sopenharmony_ci
673062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000);
673162306a36Sopenharmony_ci	tp->ocp_base = 0x2000;
673262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, 0xb014, 0x4c);		/* phy state */
673362306a36Sopenharmony_ci	nway_state = ocp_read_word(tp, MCU_TYPE_PLA, 0xb01a);
673462306a36Sopenharmony_ci
673562306a36Sopenharmony_ci	/* bit 15: TXDIS_STATE, bit 14: ABD_STATE */
673662306a36Sopenharmony_ci	if (nway_state & 0xc000)
673762306a36Sopenharmony_ci		return false;
673862306a36Sopenharmony_ci	else
673962306a36Sopenharmony_ci		return true;
674062306a36Sopenharmony_ci}
674162306a36Sopenharmony_ci
674262306a36Sopenharmony_cistatic bool rtl8153_in_nway(struct r8152 *tp)
674362306a36Sopenharmony_ci{
674462306a36Sopenharmony_ci	u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff;
674562306a36Sopenharmony_ci
674662306a36Sopenharmony_ci	if (phy_state == TXDIS_STATE || phy_state == ABD_STATE)
674762306a36Sopenharmony_ci		return false;
674862306a36Sopenharmony_ci	else
674962306a36Sopenharmony_ci		return true;
675062306a36Sopenharmony_ci}
675162306a36Sopenharmony_ci
675262306a36Sopenharmony_cistatic void r8156_mdio_force_mode(struct r8152 *tp)
675362306a36Sopenharmony_ci{
675462306a36Sopenharmony_ci	u16 data;
675562306a36Sopenharmony_ci
675662306a36Sopenharmony_ci	/* Select force mode through 0xa5b4 bit 15
675762306a36Sopenharmony_ci	 * 0: MDIO force mode
675862306a36Sopenharmony_ci	 * 1: MMD force mode
675962306a36Sopenharmony_ci	 */
676062306a36Sopenharmony_ci	data = ocp_reg_read(tp, 0xa5b4);
676162306a36Sopenharmony_ci	if (data & BIT(15)) {
676262306a36Sopenharmony_ci		data &= ~BIT(15);
676362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa5b4, data);
676462306a36Sopenharmony_ci	}
676562306a36Sopenharmony_ci}
676662306a36Sopenharmony_ci
676762306a36Sopenharmony_cistatic void set_carrier(struct r8152 *tp)
676862306a36Sopenharmony_ci{
676962306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
677062306a36Sopenharmony_ci	struct napi_struct *napi = &tp->napi;
677162306a36Sopenharmony_ci	u16 speed;
677262306a36Sopenharmony_ci
677362306a36Sopenharmony_ci	speed = rtl8152_get_speed(tp);
677462306a36Sopenharmony_ci
677562306a36Sopenharmony_ci	if (speed & LINK_STATUS) {
677662306a36Sopenharmony_ci		if (!netif_carrier_ok(netdev)) {
677762306a36Sopenharmony_ci			tp->rtl_ops.enable(tp);
677862306a36Sopenharmony_ci			netif_stop_queue(netdev);
677962306a36Sopenharmony_ci			napi_disable(napi);
678062306a36Sopenharmony_ci			netif_carrier_on(netdev);
678162306a36Sopenharmony_ci			rtl_start_rx(tp);
678262306a36Sopenharmony_ci			clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
678362306a36Sopenharmony_ci			_rtl8152_set_rx_mode(netdev);
678462306a36Sopenharmony_ci			napi_enable(napi);
678562306a36Sopenharmony_ci			netif_wake_queue(netdev);
678662306a36Sopenharmony_ci			netif_info(tp, link, netdev, "carrier on\n");
678762306a36Sopenharmony_ci		} else if (netif_queue_stopped(netdev) &&
678862306a36Sopenharmony_ci			   skb_queue_len(&tp->tx_queue) < tp->tx_qlen) {
678962306a36Sopenharmony_ci			netif_wake_queue(netdev);
679062306a36Sopenharmony_ci		}
679162306a36Sopenharmony_ci	} else {
679262306a36Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
679362306a36Sopenharmony_ci			netif_carrier_off(netdev);
679462306a36Sopenharmony_ci			tasklet_disable(&tp->tx_tl);
679562306a36Sopenharmony_ci			napi_disable(napi);
679662306a36Sopenharmony_ci			tp->rtl_ops.disable(tp);
679762306a36Sopenharmony_ci			napi_enable(napi);
679862306a36Sopenharmony_ci			tasklet_enable(&tp->tx_tl);
679962306a36Sopenharmony_ci			netif_info(tp, link, netdev, "carrier off\n");
680062306a36Sopenharmony_ci		}
680162306a36Sopenharmony_ci	}
680262306a36Sopenharmony_ci}
680362306a36Sopenharmony_ci
680462306a36Sopenharmony_cistatic void rtl_work_func_t(struct work_struct *work)
680562306a36Sopenharmony_ci{
680662306a36Sopenharmony_ci	struct r8152 *tp = container_of(work, struct r8152, schedule.work);
680762306a36Sopenharmony_ci
680862306a36Sopenharmony_ci	/* If the device is unplugged or !netif_running(), the workqueue
680962306a36Sopenharmony_ci	 * doesn't need to wake the device, and could return directly.
681062306a36Sopenharmony_ci	 */
681162306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags) || !netif_running(tp->netdev))
681262306a36Sopenharmony_ci		return;
681362306a36Sopenharmony_ci
681462306a36Sopenharmony_ci	if (usb_autopm_get_interface(tp->intf) < 0)
681562306a36Sopenharmony_ci		return;
681662306a36Sopenharmony_ci
681762306a36Sopenharmony_ci	if (!test_bit(WORK_ENABLE, &tp->flags))
681862306a36Sopenharmony_ci		goto out1;
681962306a36Sopenharmony_ci
682062306a36Sopenharmony_ci	if (!mutex_trylock(&tp->control)) {
682162306a36Sopenharmony_ci		schedule_delayed_work(&tp->schedule, 0);
682262306a36Sopenharmony_ci		goto out1;
682362306a36Sopenharmony_ci	}
682462306a36Sopenharmony_ci
682562306a36Sopenharmony_ci	if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags))
682662306a36Sopenharmony_ci		set_carrier(tp);
682762306a36Sopenharmony_ci
682862306a36Sopenharmony_ci	if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags))
682962306a36Sopenharmony_ci		_rtl8152_set_rx_mode(tp->netdev);
683062306a36Sopenharmony_ci
683162306a36Sopenharmony_ci	/* don't schedule tasket before linking */
683262306a36Sopenharmony_ci	if (test_and_clear_bit(SCHEDULE_TASKLET, &tp->flags) &&
683362306a36Sopenharmony_ci	    netif_carrier_ok(tp->netdev))
683462306a36Sopenharmony_ci		tasklet_schedule(&tp->tx_tl);
683562306a36Sopenharmony_ci
683662306a36Sopenharmony_ci	if (test_and_clear_bit(RX_EPROTO, &tp->flags) &&
683762306a36Sopenharmony_ci	    !list_empty(&tp->rx_done))
683862306a36Sopenharmony_ci		napi_schedule(&tp->napi);
683962306a36Sopenharmony_ci
684062306a36Sopenharmony_ci	mutex_unlock(&tp->control);
684162306a36Sopenharmony_ci
684262306a36Sopenharmony_ciout1:
684362306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
684462306a36Sopenharmony_ci}
684562306a36Sopenharmony_ci
684662306a36Sopenharmony_cistatic void rtl_hw_phy_work_func_t(struct work_struct *work)
684762306a36Sopenharmony_ci{
684862306a36Sopenharmony_ci	struct r8152 *tp = container_of(work, struct r8152, hw_phy_work.work);
684962306a36Sopenharmony_ci
685062306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
685162306a36Sopenharmony_ci		return;
685262306a36Sopenharmony_ci
685362306a36Sopenharmony_ci	if (usb_autopm_get_interface(tp->intf) < 0)
685462306a36Sopenharmony_ci		return;
685562306a36Sopenharmony_ci
685662306a36Sopenharmony_ci	mutex_lock(&tp->control);
685762306a36Sopenharmony_ci
685862306a36Sopenharmony_ci	if (rtl8152_request_firmware(tp) == -ENODEV && tp->rtl_fw.retry) {
685962306a36Sopenharmony_ci		tp->rtl_fw.retry = false;
686062306a36Sopenharmony_ci		tp->rtl_fw.fw = NULL;
686162306a36Sopenharmony_ci
686262306a36Sopenharmony_ci		/* Delay execution in case request_firmware() is not ready yet.
686362306a36Sopenharmony_ci		 */
686462306a36Sopenharmony_ci		queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10);
686562306a36Sopenharmony_ci		goto ignore_once;
686662306a36Sopenharmony_ci	}
686762306a36Sopenharmony_ci
686862306a36Sopenharmony_ci	tp->rtl_ops.hw_phy_cfg(tp);
686962306a36Sopenharmony_ci
687062306a36Sopenharmony_ci	rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex,
687162306a36Sopenharmony_ci			  tp->advertising);
687262306a36Sopenharmony_ci
687362306a36Sopenharmony_ciignore_once:
687462306a36Sopenharmony_ci	mutex_unlock(&tp->control);
687562306a36Sopenharmony_ci
687662306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
687762306a36Sopenharmony_ci}
687862306a36Sopenharmony_ci
687962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
688062306a36Sopenharmony_cistatic int rtl_notifier(struct notifier_block *nb, unsigned long action,
688162306a36Sopenharmony_ci			void *data)
688262306a36Sopenharmony_ci{
688362306a36Sopenharmony_ci	struct r8152 *tp = container_of(nb, struct r8152, pm_notifier);
688462306a36Sopenharmony_ci
688562306a36Sopenharmony_ci	switch (action) {
688662306a36Sopenharmony_ci	case PM_HIBERNATION_PREPARE:
688762306a36Sopenharmony_ci	case PM_SUSPEND_PREPARE:
688862306a36Sopenharmony_ci		usb_autopm_get_interface(tp->intf);
688962306a36Sopenharmony_ci		break;
689062306a36Sopenharmony_ci
689162306a36Sopenharmony_ci	case PM_POST_HIBERNATION:
689262306a36Sopenharmony_ci	case PM_POST_SUSPEND:
689362306a36Sopenharmony_ci		usb_autopm_put_interface(tp->intf);
689462306a36Sopenharmony_ci		break;
689562306a36Sopenharmony_ci
689662306a36Sopenharmony_ci	case PM_POST_RESTORE:
689762306a36Sopenharmony_ci	case PM_RESTORE_PREPARE:
689862306a36Sopenharmony_ci	default:
689962306a36Sopenharmony_ci		break;
690062306a36Sopenharmony_ci	}
690162306a36Sopenharmony_ci
690262306a36Sopenharmony_ci	return NOTIFY_DONE;
690362306a36Sopenharmony_ci}
690462306a36Sopenharmony_ci#endif
690562306a36Sopenharmony_ci
690662306a36Sopenharmony_cistatic int rtl8152_open(struct net_device *netdev)
690762306a36Sopenharmony_ci{
690862306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
690962306a36Sopenharmony_ci	int res = 0;
691062306a36Sopenharmony_ci
691162306a36Sopenharmony_ci	if (work_busy(&tp->hw_phy_work.work) & WORK_BUSY_PENDING) {
691262306a36Sopenharmony_ci		cancel_delayed_work_sync(&tp->hw_phy_work);
691362306a36Sopenharmony_ci		rtl_hw_phy_work_func_t(&tp->hw_phy_work.work);
691462306a36Sopenharmony_ci	}
691562306a36Sopenharmony_ci
691662306a36Sopenharmony_ci	res = alloc_all_mem(tp);
691762306a36Sopenharmony_ci	if (res)
691862306a36Sopenharmony_ci		goto out;
691962306a36Sopenharmony_ci
692062306a36Sopenharmony_ci	res = usb_autopm_get_interface(tp->intf);
692162306a36Sopenharmony_ci	if (res < 0)
692262306a36Sopenharmony_ci		goto out_free;
692362306a36Sopenharmony_ci
692462306a36Sopenharmony_ci	mutex_lock(&tp->control);
692562306a36Sopenharmony_ci
692662306a36Sopenharmony_ci	tp->rtl_ops.up(tp);
692762306a36Sopenharmony_ci
692862306a36Sopenharmony_ci	netif_carrier_off(netdev);
692962306a36Sopenharmony_ci	netif_start_queue(netdev);
693062306a36Sopenharmony_ci	set_bit(WORK_ENABLE, &tp->flags);
693162306a36Sopenharmony_ci
693262306a36Sopenharmony_ci	res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
693362306a36Sopenharmony_ci	if (res) {
693462306a36Sopenharmony_ci		if (res == -ENODEV)
693562306a36Sopenharmony_ci			netif_device_detach(tp->netdev);
693662306a36Sopenharmony_ci		netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
693762306a36Sopenharmony_ci			   res);
693862306a36Sopenharmony_ci		goto out_unlock;
693962306a36Sopenharmony_ci	}
694062306a36Sopenharmony_ci	napi_enable(&tp->napi);
694162306a36Sopenharmony_ci	tasklet_enable(&tp->tx_tl);
694262306a36Sopenharmony_ci
694362306a36Sopenharmony_ci	mutex_unlock(&tp->control);
694462306a36Sopenharmony_ci
694562306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
694662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
694762306a36Sopenharmony_ci	tp->pm_notifier.notifier_call = rtl_notifier;
694862306a36Sopenharmony_ci	register_pm_notifier(&tp->pm_notifier);
694962306a36Sopenharmony_ci#endif
695062306a36Sopenharmony_ci	return 0;
695162306a36Sopenharmony_ci
695262306a36Sopenharmony_ciout_unlock:
695362306a36Sopenharmony_ci	mutex_unlock(&tp->control);
695462306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
695562306a36Sopenharmony_ciout_free:
695662306a36Sopenharmony_ci	free_all_mem(tp);
695762306a36Sopenharmony_ciout:
695862306a36Sopenharmony_ci	return res;
695962306a36Sopenharmony_ci}
696062306a36Sopenharmony_ci
696162306a36Sopenharmony_cistatic int rtl8152_close(struct net_device *netdev)
696262306a36Sopenharmony_ci{
696362306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
696462306a36Sopenharmony_ci	int res = 0;
696562306a36Sopenharmony_ci
696662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
696762306a36Sopenharmony_ci	unregister_pm_notifier(&tp->pm_notifier);
696862306a36Sopenharmony_ci#endif
696962306a36Sopenharmony_ci	tasklet_disable(&tp->tx_tl);
697062306a36Sopenharmony_ci	clear_bit(WORK_ENABLE, &tp->flags);
697162306a36Sopenharmony_ci	usb_kill_urb(tp->intr_urb);
697262306a36Sopenharmony_ci	cancel_delayed_work_sync(&tp->schedule);
697362306a36Sopenharmony_ci	napi_disable(&tp->napi);
697462306a36Sopenharmony_ci	netif_stop_queue(netdev);
697562306a36Sopenharmony_ci
697662306a36Sopenharmony_ci	res = usb_autopm_get_interface(tp->intf);
697762306a36Sopenharmony_ci	if (res < 0 || test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
697862306a36Sopenharmony_ci		rtl_drop_queued_tx(tp);
697962306a36Sopenharmony_ci		rtl_stop_rx(tp);
698062306a36Sopenharmony_ci	} else {
698162306a36Sopenharmony_ci		mutex_lock(&tp->control);
698262306a36Sopenharmony_ci
698362306a36Sopenharmony_ci		tp->rtl_ops.down(tp);
698462306a36Sopenharmony_ci
698562306a36Sopenharmony_ci		mutex_unlock(&tp->control);
698662306a36Sopenharmony_ci	}
698762306a36Sopenharmony_ci
698862306a36Sopenharmony_ci	if (!res)
698962306a36Sopenharmony_ci		usb_autopm_put_interface(tp->intf);
699062306a36Sopenharmony_ci
699162306a36Sopenharmony_ci	free_all_mem(tp);
699262306a36Sopenharmony_ci
699362306a36Sopenharmony_ci	return res;
699462306a36Sopenharmony_ci}
699562306a36Sopenharmony_ci
699662306a36Sopenharmony_cistatic void rtl_tally_reset(struct r8152 *tp)
699762306a36Sopenharmony_ci{
699862306a36Sopenharmony_ci	u32 ocp_data;
699962306a36Sopenharmony_ci
700062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
700162306a36Sopenharmony_ci	ocp_data |= TALLY_RESET;
700262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
700362306a36Sopenharmony_ci}
700462306a36Sopenharmony_ci
700562306a36Sopenharmony_cistatic void r8152b_init(struct r8152 *tp)
700662306a36Sopenharmony_ci{
700762306a36Sopenharmony_ci	u32 ocp_data;
700862306a36Sopenharmony_ci	u16 data;
700962306a36Sopenharmony_ci
701062306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
701162306a36Sopenharmony_ci		return;
701262306a36Sopenharmony_ci
701362306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
701462306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
701562306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
701662306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
701762306a36Sopenharmony_ci	}
701862306a36Sopenharmony_ci
701962306a36Sopenharmony_ci	r8152_aldps_en(tp, false);
702062306a36Sopenharmony_ci
702162306a36Sopenharmony_ci	if (tp->version == RTL_VER_01) {
702262306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
702362306a36Sopenharmony_ci		ocp_data &= ~LED_MODE_MASK;
702462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
702562306a36Sopenharmony_ci	}
702662306a36Sopenharmony_ci
702762306a36Sopenharmony_ci	r8152_power_cut_en(tp, false);
702862306a36Sopenharmony_ci
702962306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
703062306a36Sopenharmony_ci	ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
703162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
703262306a36Sopenharmony_ci	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
703362306a36Sopenharmony_ci	ocp_data &= ~MCU_CLK_RATIO_MASK;
703462306a36Sopenharmony_ci	ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
703562306a36Sopenharmony_ci	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
703662306a36Sopenharmony_ci	ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
703762306a36Sopenharmony_ci		   SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
703862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
703962306a36Sopenharmony_ci
704062306a36Sopenharmony_ci	rtl_tally_reset(tp);
704162306a36Sopenharmony_ci
704262306a36Sopenharmony_ci	/* enable rx aggregation */
704362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
704462306a36Sopenharmony_ci	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
704562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
704662306a36Sopenharmony_ci}
704762306a36Sopenharmony_ci
704862306a36Sopenharmony_cistatic void r8153_init(struct r8152 *tp)
704962306a36Sopenharmony_ci{
705062306a36Sopenharmony_ci	u32 ocp_data;
705162306a36Sopenharmony_ci	u16 data;
705262306a36Sopenharmony_ci	int i;
705362306a36Sopenharmony_ci
705462306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
705562306a36Sopenharmony_ci		return;
705662306a36Sopenharmony_ci
705762306a36Sopenharmony_ci	r8153_u1u2en(tp, false);
705862306a36Sopenharmony_ci
705962306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
706062306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
706162306a36Sopenharmony_ci		    AUTOLOAD_DONE)
706262306a36Sopenharmony_ci			break;
706362306a36Sopenharmony_ci
706462306a36Sopenharmony_ci		msleep(20);
706562306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
706662306a36Sopenharmony_ci			break;
706762306a36Sopenharmony_ci	}
706862306a36Sopenharmony_ci
706962306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
707062306a36Sopenharmony_ci
707162306a36Sopenharmony_ci	if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 ||
707262306a36Sopenharmony_ci	    tp->version == RTL_VER_05)
707362306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L);
707462306a36Sopenharmony_ci
707562306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
707662306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
707762306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
707862306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
707962306a36Sopenharmony_ci	}
708062306a36Sopenharmony_ci
708162306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
708262306a36Sopenharmony_ci
708362306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
708462306a36Sopenharmony_ci
708562306a36Sopenharmony_ci	if (tp->version == RTL_VER_04) {
708662306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2);
708762306a36Sopenharmony_ci		ocp_data &= ~pwd_dn_scale_mask;
708862306a36Sopenharmony_ci		ocp_data |= pwd_dn_scale(96);
708962306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data);
709062306a36Sopenharmony_ci
709162306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
709262306a36Sopenharmony_ci		ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
709362306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
709462306a36Sopenharmony_ci	} else if (tp->version == RTL_VER_05) {
709562306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0);
709662306a36Sopenharmony_ci		ocp_data &= ~ECM_ALDPS;
709762306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data);
709862306a36Sopenharmony_ci
709962306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
710062306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
710162306a36Sopenharmony_ci			ocp_data &= ~DYNAMIC_BURST;
710262306a36Sopenharmony_ci		else
710362306a36Sopenharmony_ci			ocp_data |= DYNAMIC_BURST;
710462306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
710562306a36Sopenharmony_ci	} else if (tp->version == RTL_VER_06) {
710662306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
710762306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
710862306a36Sopenharmony_ci			ocp_data &= ~DYNAMIC_BURST;
710962306a36Sopenharmony_ci		else
711062306a36Sopenharmony_ci			ocp_data |= DYNAMIC_BURST;
711162306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
711262306a36Sopenharmony_ci
711362306a36Sopenharmony_ci		r8153_queue_wake(tp, false);
711462306a36Sopenharmony_ci
711562306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
711662306a36Sopenharmony_ci		if (rtl8152_get_speed(tp) & LINK_STATUS)
711762306a36Sopenharmony_ci			ocp_data |= CUR_LINK_OK;
711862306a36Sopenharmony_ci		else
711962306a36Sopenharmony_ci			ocp_data &= ~CUR_LINK_OK;
712062306a36Sopenharmony_ci		ocp_data |= POLL_LINK_CHG;
712162306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
712262306a36Sopenharmony_ci	}
712362306a36Sopenharmony_ci
712462306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2);
712562306a36Sopenharmony_ci	ocp_data |= EP4_FULL_FC;
712662306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data);
712762306a36Sopenharmony_ci
712862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
712962306a36Sopenharmony_ci	ocp_data &= ~TIMER11_EN;
713062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
713162306a36Sopenharmony_ci
713262306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
713362306a36Sopenharmony_ci	ocp_data &= ~LED_MODE_MASK;
713462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
713562306a36Sopenharmony_ci
713662306a36Sopenharmony_ci	ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM;
713762306a36Sopenharmony_ci	if (tp->version == RTL_VER_04 && tp->udev->speed < USB_SPEED_SUPER)
713862306a36Sopenharmony_ci		ocp_data |= LPM_TIMER_500MS;
713962306a36Sopenharmony_ci	else
714062306a36Sopenharmony_ci		ocp_data |= LPM_TIMER_500US;
714162306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data);
714262306a36Sopenharmony_ci
714362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2);
714462306a36Sopenharmony_ci	ocp_data &= ~SEN_VAL_MASK;
714562306a36Sopenharmony_ci	ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
714662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
714762306a36Sopenharmony_ci
714862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
714962306a36Sopenharmony_ci
715062306a36Sopenharmony_ci	r8153_power_cut_en(tp, false);
715162306a36Sopenharmony_ci	rtl_runtime_suspend_enable(tp, false);
715262306a36Sopenharmony_ci	r8153_mac_clk_speed_down(tp, false);
715362306a36Sopenharmony_ci	r8153_u1u2en(tp, true);
715462306a36Sopenharmony_ci	usb_enable_lpm(tp->udev);
715562306a36Sopenharmony_ci
715662306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
715762306a36Sopenharmony_ci	ocp_data |= LANWAKE_CLR_EN;
715862306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data);
715962306a36Sopenharmony_ci
716062306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG);
716162306a36Sopenharmony_ci	ocp_data &= ~LANWAKE_PIN;
716262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data);
716362306a36Sopenharmony_ci
716462306a36Sopenharmony_ci	/* rx aggregation */
716562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
716662306a36Sopenharmony_ci	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
716762306a36Sopenharmony_ci	if (tp->dell_tb_rx_agg_bug)
716862306a36Sopenharmony_ci		ocp_data |= RX_AGG_DISABLE;
716962306a36Sopenharmony_ci
717062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
717162306a36Sopenharmony_ci
717262306a36Sopenharmony_ci	rtl_tally_reset(tp);
717362306a36Sopenharmony_ci
717462306a36Sopenharmony_ci	switch (tp->udev->speed) {
717562306a36Sopenharmony_ci	case USB_SPEED_SUPER:
717662306a36Sopenharmony_ci	case USB_SPEED_SUPER_PLUS:
717762306a36Sopenharmony_ci		tp->coalesce = COALESCE_SUPER;
717862306a36Sopenharmony_ci		break;
717962306a36Sopenharmony_ci	case USB_SPEED_HIGH:
718062306a36Sopenharmony_ci		tp->coalesce = COALESCE_HIGH;
718162306a36Sopenharmony_ci		break;
718262306a36Sopenharmony_ci	default:
718362306a36Sopenharmony_ci		tp->coalesce = COALESCE_SLOW;
718462306a36Sopenharmony_ci		break;
718562306a36Sopenharmony_ci	}
718662306a36Sopenharmony_ci}
718762306a36Sopenharmony_ci
718862306a36Sopenharmony_cistatic void r8153b_init(struct r8152 *tp)
718962306a36Sopenharmony_ci{
719062306a36Sopenharmony_ci	u32 ocp_data;
719162306a36Sopenharmony_ci	u16 data;
719262306a36Sopenharmony_ci	int i;
719362306a36Sopenharmony_ci
719462306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
719562306a36Sopenharmony_ci		return;
719662306a36Sopenharmony_ci
719762306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
719862306a36Sopenharmony_ci
719962306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
720062306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
720162306a36Sopenharmony_ci		    AUTOLOAD_DONE)
720262306a36Sopenharmony_ci			break;
720362306a36Sopenharmony_ci
720462306a36Sopenharmony_ci		msleep(20);
720562306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
720662306a36Sopenharmony_ci			break;
720762306a36Sopenharmony_ci	}
720862306a36Sopenharmony_ci
720962306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
721062306a36Sopenharmony_ci
721162306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
721262306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
721362306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
721462306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
721562306a36Sopenharmony_ci	}
721662306a36Sopenharmony_ci
721762306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
721862306a36Sopenharmony_ci
721962306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
722062306a36Sopenharmony_ci
722162306a36Sopenharmony_ci	/* MSC timer = 0xfff * 8ms = 32760 ms */
722262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
722362306a36Sopenharmony_ci
722462306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
722562306a36Sopenharmony_ci	r8153b_ups_en(tp, false);
722662306a36Sopenharmony_ci	r8153_queue_wake(tp, false);
722762306a36Sopenharmony_ci	rtl_runtime_suspend_enable(tp, false);
722862306a36Sopenharmony_ci
722962306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
723062306a36Sopenharmony_ci	if (rtl8152_get_speed(tp) & LINK_STATUS)
723162306a36Sopenharmony_ci		ocp_data |= CUR_LINK_OK;
723262306a36Sopenharmony_ci	else
723362306a36Sopenharmony_ci		ocp_data &= ~CUR_LINK_OK;
723462306a36Sopenharmony_ci	ocp_data |= POLL_LINK_CHG;
723562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
723662306a36Sopenharmony_ci
723762306a36Sopenharmony_ci	if (tp->udev->speed >= USB_SPEED_SUPER)
723862306a36Sopenharmony_ci		r8153b_u1u2en(tp, true);
723962306a36Sopenharmony_ci
724062306a36Sopenharmony_ci	usb_enable_lpm(tp->udev);
724162306a36Sopenharmony_ci
724262306a36Sopenharmony_ci	/* MAC clock speed down */
724362306a36Sopenharmony_ci	r8153_mac_clk_speed_down(tp, true);
724462306a36Sopenharmony_ci
724562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
724662306a36Sopenharmony_ci	ocp_data &= ~PLA_MCU_SPDWN_EN;
724762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
724862306a36Sopenharmony_ci
724962306a36Sopenharmony_ci	if (tp->version == RTL_VER_09) {
725062306a36Sopenharmony_ci		/* Disable Test IO for 32QFN */
725162306a36Sopenharmony_ci		if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) {
725262306a36Sopenharmony_ci			ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
725362306a36Sopenharmony_ci			ocp_data |= TEST_IO_OFF;
725462306a36Sopenharmony_ci			ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
725562306a36Sopenharmony_ci		}
725662306a36Sopenharmony_ci	}
725762306a36Sopenharmony_ci
725862306a36Sopenharmony_ci	set_bit(GREEN_ETHERNET, &tp->flags);
725962306a36Sopenharmony_ci
726062306a36Sopenharmony_ci	/* rx aggregation */
726162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
726262306a36Sopenharmony_ci	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
726362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
726462306a36Sopenharmony_ci
726562306a36Sopenharmony_ci	rtl_tally_reset(tp);
726662306a36Sopenharmony_ci
726762306a36Sopenharmony_ci	tp->coalesce = 15000;	/* 15 us */
726862306a36Sopenharmony_ci}
726962306a36Sopenharmony_ci
727062306a36Sopenharmony_cistatic void r8153c_init(struct r8152 *tp)
727162306a36Sopenharmony_ci{
727262306a36Sopenharmony_ci	u32 ocp_data;
727362306a36Sopenharmony_ci	u16 data;
727462306a36Sopenharmony_ci	int i;
727562306a36Sopenharmony_ci
727662306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
727762306a36Sopenharmony_ci		return;
727862306a36Sopenharmony_ci
727962306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
728062306a36Sopenharmony_ci
728162306a36Sopenharmony_ci	/* Disable spi_en */
728262306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
728362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
728462306a36Sopenharmony_ci	ocp_data &= ~BIT(3);
728562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
728662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xcbf0);
728762306a36Sopenharmony_ci	ocp_data |= BIT(1);
728862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, 0xcbf0, ocp_data);
728962306a36Sopenharmony_ci
729062306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
729162306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
729262306a36Sopenharmony_ci		    AUTOLOAD_DONE)
729362306a36Sopenharmony_ci			break;
729462306a36Sopenharmony_ci
729562306a36Sopenharmony_ci		msleep(20);
729662306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
729762306a36Sopenharmony_ci			return;
729862306a36Sopenharmony_ci	}
729962306a36Sopenharmony_ci
730062306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
730162306a36Sopenharmony_ci
730262306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
730362306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
730462306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
730562306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
730662306a36Sopenharmony_ci	}
730762306a36Sopenharmony_ci
730862306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
730962306a36Sopenharmony_ci
731062306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
731162306a36Sopenharmony_ci
731262306a36Sopenharmony_ci	/* MSC timer = 0xfff * 8ms = 32760 ms */
731362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
731462306a36Sopenharmony_ci
731562306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
731662306a36Sopenharmony_ci	r8153c_ups_en(tp, false);
731762306a36Sopenharmony_ci	r8153_queue_wake(tp, false);
731862306a36Sopenharmony_ci	rtl_runtime_suspend_enable(tp, false);
731962306a36Sopenharmony_ci
732062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
732162306a36Sopenharmony_ci	if (rtl8152_get_speed(tp) & LINK_STATUS)
732262306a36Sopenharmony_ci		ocp_data |= CUR_LINK_OK;
732362306a36Sopenharmony_ci	else
732462306a36Sopenharmony_ci		ocp_data &= ~CUR_LINK_OK;
732562306a36Sopenharmony_ci
732662306a36Sopenharmony_ci	ocp_data |= POLL_LINK_CHG;
732762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
732862306a36Sopenharmony_ci
732962306a36Sopenharmony_ci	r8153b_u1u2en(tp, true);
733062306a36Sopenharmony_ci
733162306a36Sopenharmony_ci	usb_enable_lpm(tp->udev);
733262306a36Sopenharmony_ci
733362306a36Sopenharmony_ci	/* MAC clock speed down */
733462306a36Sopenharmony_ci	r8153_mac_clk_speed_down(tp, true);
733562306a36Sopenharmony_ci
733662306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
733762306a36Sopenharmony_ci	ocp_data &= ~BIT(7);
733862306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
733962306a36Sopenharmony_ci
734062306a36Sopenharmony_ci	set_bit(GREEN_ETHERNET, &tp->flags);
734162306a36Sopenharmony_ci
734262306a36Sopenharmony_ci	/* rx aggregation */
734362306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
734462306a36Sopenharmony_ci	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
734562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
734662306a36Sopenharmony_ci
734762306a36Sopenharmony_ci	rtl_tally_reset(tp);
734862306a36Sopenharmony_ci
734962306a36Sopenharmony_ci	tp->coalesce = 15000;	/* 15 us */
735062306a36Sopenharmony_ci}
735162306a36Sopenharmony_ci
735262306a36Sopenharmony_cistatic void r8156_hw_phy_cfg(struct r8152 *tp)
735362306a36Sopenharmony_ci{
735462306a36Sopenharmony_ci	u32 ocp_data;
735562306a36Sopenharmony_ci	u16 data;
735662306a36Sopenharmony_ci
735762306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
735862306a36Sopenharmony_ci	if (ocp_data & PCUT_STATUS) {
735962306a36Sopenharmony_ci		ocp_data &= ~PCUT_STATUS;
736062306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
736162306a36Sopenharmony_ci	}
736262306a36Sopenharmony_ci
736362306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
736462306a36Sopenharmony_ci	switch (data) {
736562306a36Sopenharmony_ci	case PHY_STAT_EXT_INIT:
736662306a36Sopenharmony_ci		rtl8152_apply_firmware(tp, true);
736762306a36Sopenharmony_ci
736862306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa468);
736962306a36Sopenharmony_ci		data &= ~(BIT(3) | BIT(1));
737062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa468, data);
737162306a36Sopenharmony_ci		break;
737262306a36Sopenharmony_ci	case PHY_STAT_LAN_ON:
737362306a36Sopenharmony_ci	case PHY_STAT_PWRDN:
737462306a36Sopenharmony_ci	default:
737562306a36Sopenharmony_ci		rtl8152_apply_firmware(tp, false);
737662306a36Sopenharmony_ci		break;
737762306a36Sopenharmony_ci	}
737862306a36Sopenharmony_ci
737962306a36Sopenharmony_ci	/* disable ALDPS before updating the PHY parameters */
738062306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
738162306a36Sopenharmony_ci
738262306a36Sopenharmony_ci	/* disable EEE before updating the PHY parameters */
738362306a36Sopenharmony_ci	rtl_eee_enable(tp, false);
738462306a36Sopenharmony_ci
738562306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
738662306a36Sopenharmony_ci	WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
738762306a36Sopenharmony_ci
738862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
738962306a36Sopenharmony_ci	ocp_data |= PFM_PWM_SWITCH;
739062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
739162306a36Sopenharmony_ci
739262306a36Sopenharmony_ci	switch (tp->version) {
739362306a36Sopenharmony_ci	case RTL_VER_10:
739462306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad40);
739562306a36Sopenharmony_ci		data &= ~0x3ff;
739662306a36Sopenharmony_ci		data |= BIT(7) | BIT(2);
739762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad40, data);
739862306a36Sopenharmony_ci
739962306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad4e);
740062306a36Sopenharmony_ci		data |= BIT(4);
740162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad4e, data);
740262306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad16);
740362306a36Sopenharmony_ci		data &= ~0x3ff;
740462306a36Sopenharmony_ci		data |= 0x6;
740562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad16, data);
740662306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad32);
740762306a36Sopenharmony_ci		data &= ~0x3f;
740862306a36Sopenharmony_ci		data |= 6;
740962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad32, data);
741062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac08);
741162306a36Sopenharmony_ci		data &= ~(BIT(12) | BIT(8));
741262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac08, data);
741362306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac8a);
741462306a36Sopenharmony_ci		data |= BIT(12) | BIT(13) | BIT(14);
741562306a36Sopenharmony_ci		data &= ~BIT(15);
741662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac8a, data);
741762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad18);
741862306a36Sopenharmony_ci		data |= BIT(10);
741962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad18, data);
742062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad1a);
742162306a36Sopenharmony_ci		data |= 0x3ff;
742262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad1a, data);
742362306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad1c);
742462306a36Sopenharmony_ci		data |= 0x3ff;
742562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad1c, data);
742662306a36Sopenharmony_ci
742762306a36Sopenharmony_ci		data = sram_read(tp, 0x80ea);
742862306a36Sopenharmony_ci		data &= ~0xff00;
742962306a36Sopenharmony_ci		data |= 0xc400;
743062306a36Sopenharmony_ci		sram_write(tp, 0x80ea, data);
743162306a36Sopenharmony_ci		data = sram_read(tp, 0x80eb);
743262306a36Sopenharmony_ci		data &= ~0x0700;
743362306a36Sopenharmony_ci		data |= 0x0300;
743462306a36Sopenharmony_ci		sram_write(tp, 0x80eb, data);
743562306a36Sopenharmony_ci		data = sram_read(tp, 0x80f8);
743662306a36Sopenharmony_ci		data &= ~0xff00;
743762306a36Sopenharmony_ci		data |= 0x1c00;
743862306a36Sopenharmony_ci		sram_write(tp, 0x80f8, data);
743962306a36Sopenharmony_ci		data = sram_read(tp, 0x80f1);
744062306a36Sopenharmony_ci		data &= ~0xff00;
744162306a36Sopenharmony_ci		data |= 0x3000;
744262306a36Sopenharmony_ci		sram_write(tp, 0x80f1, data);
744362306a36Sopenharmony_ci
744462306a36Sopenharmony_ci		data = sram_read(tp, 0x80fe);
744562306a36Sopenharmony_ci		data &= ~0xff00;
744662306a36Sopenharmony_ci		data |= 0xa500;
744762306a36Sopenharmony_ci		sram_write(tp, 0x80fe, data);
744862306a36Sopenharmony_ci		data = sram_read(tp, 0x8102);
744962306a36Sopenharmony_ci		data &= ~0xff00;
745062306a36Sopenharmony_ci		data |= 0x5000;
745162306a36Sopenharmony_ci		sram_write(tp, 0x8102, data);
745262306a36Sopenharmony_ci		data = sram_read(tp, 0x8015);
745362306a36Sopenharmony_ci		data &= ~0xff00;
745462306a36Sopenharmony_ci		data |= 0x3300;
745562306a36Sopenharmony_ci		sram_write(tp, 0x8015, data);
745662306a36Sopenharmony_ci		data = sram_read(tp, 0x8100);
745762306a36Sopenharmony_ci		data &= ~0xff00;
745862306a36Sopenharmony_ci		data |= 0x7000;
745962306a36Sopenharmony_ci		sram_write(tp, 0x8100, data);
746062306a36Sopenharmony_ci		data = sram_read(tp, 0x8014);
746162306a36Sopenharmony_ci		data &= ~0xff00;
746262306a36Sopenharmony_ci		data |= 0xf000;
746362306a36Sopenharmony_ci		sram_write(tp, 0x8014, data);
746462306a36Sopenharmony_ci		data = sram_read(tp, 0x8016);
746562306a36Sopenharmony_ci		data &= ~0xff00;
746662306a36Sopenharmony_ci		data |= 0x6500;
746762306a36Sopenharmony_ci		sram_write(tp, 0x8016, data);
746862306a36Sopenharmony_ci		data = sram_read(tp, 0x80dc);
746962306a36Sopenharmony_ci		data &= ~0xff00;
747062306a36Sopenharmony_ci		data |= 0xed00;
747162306a36Sopenharmony_ci		sram_write(tp, 0x80dc, data);
747262306a36Sopenharmony_ci		data = sram_read(tp, 0x80df);
747362306a36Sopenharmony_ci		data |= BIT(8);
747462306a36Sopenharmony_ci		sram_write(tp, 0x80df, data);
747562306a36Sopenharmony_ci		data = sram_read(tp, 0x80e1);
747662306a36Sopenharmony_ci		data &= ~BIT(8);
747762306a36Sopenharmony_ci		sram_write(tp, 0x80e1, data);
747862306a36Sopenharmony_ci
747962306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf06);
748062306a36Sopenharmony_ci		data &= ~0x003f;
748162306a36Sopenharmony_ci		data |= 0x0038;
748262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf06, data);
748362306a36Sopenharmony_ci
748462306a36Sopenharmony_ci		sram_write(tp, 0x819f, 0xddb6);
748562306a36Sopenharmony_ci
748662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbc34, 0x5555);
748762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf0a);
748862306a36Sopenharmony_ci		data &= ~0x0e00;
748962306a36Sopenharmony_ci		data |= 0x0a00;
749062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf0a, data);
749162306a36Sopenharmony_ci
749262306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbd2c);
749362306a36Sopenharmony_ci		data &= ~BIT(13);
749462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbd2c, data);
749562306a36Sopenharmony_ci		break;
749662306a36Sopenharmony_ci	case RTL_VER_11:
749762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad16);
749862306a36Sopenharmony_ci		data |= 0x3ff;
749962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad16, data);
750062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad32);
750162306a36Sopenharmony_ci		data &= ~0x3f;
750262306a36Sopenharmony_ci		data |= 6;
750362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad32, data);
750462306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac08);
750562306a36Sopenharmony_ci		data &= ~(BIT(12) | BIT(8));
750662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac08, data);
750762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xacc0);
750862306a36Sopenharmony_ci		data &= ~0x3;
750962306a36Sopenharmony_ci		data |= BIT(1);
751062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xacc0, data);
751162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad40);
751262306a36Sopenharmony_ci		data &= ~0xe7;
751362306a36Sopenharmony_ci		data |= BIT(6) | BIT(2);
751462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad40, data);
751562306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac14);
751662306a36Sopenharmony_ci		data &= ~BIT(7);
751762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac14, data);
751862306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac80);
751962306a36Sopenharmony_ci		data &= ~(BIT(8) | BIT(9));
752062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac80, data);
752162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac5e);
752262306a36Sopenharmony_ci		data &= ~0x7;
752362306a36Sopenharmony_ci		data |= BIT(1);
752462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac5e, data);
752562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad4c, 0x00a8);
752662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac5c, 0x01ff);
752762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac8a);
752862306a36Sopenharmony_ci		data &= ~0xf0;
752962306a36Sopenharmony_ci		data |= BIT(4) | BIT(5);
753062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac8a, data);
753162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8157);
753262306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb87e);
753362306a36Sopenharmony_ci		data &= ~0xff00;
753462306a36Sopenharmony_ci		data |= 0x0500;
753562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, data);
753662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8159);
753762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb87e);
753862306a36Sopenharmony_ci		data &= ~0xff00;
753962306a36Sopenharmony_ci		data |= 0x0700;
754062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, data);
754162306a36Sopenharmony_ci
754262306a36Sopenharmony_ci		/* AAGC */
754362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x80a2);
754462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0153);
754562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x809c);
754662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0153);
754762306a36Sopenharmony_ci
754862306a36Sopenharmony_ci		/* EEE parameter */
754962306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS_2P5G, 0x0056);
755062306a36Sopenharmony_ci
755162306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_USB_CFG);
755262306a36Sopenharmony_ci		ocp_data |= EN_XG_LIP | EN_G_LIP;
755362306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_USB_CFG, ocp_data);
755462306a36Sopenharmony_ci
755562306a36Sopenharmony_ci		sram_write(tp, 0x8257, 0x020f); /*  XG PLL */
755662306a36Sopenharmony_ci		sram_write(tp, 0x80ea, 0x7843); /* GIGA Master */
755762306a36Sopenharmony_ci
755862306a36Sopenharmony_ci		if (rtl_phy_patch_request(tp, true, true))
755962306a36Sopenharmony_ci			return;
756062306a36Sopenharmony_ci
756162306a36Sopenharmony_ci		/* Advance EEE */
756262306a36Sopenharmony_ci		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
756362306a36Sopenharmony_ci		ocp_data |= EEE_SPDWN_EN;
756462306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
756562306a36Sopenharmony_ci
756662306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_DOWN_SPEED);
756762306a36Sopenharmony_ci		data &= ~(EN_EEE_100 | EN_EEE_1000);
756862306a36Sopenharmony_ci		data |= EN_10M_CLKDIV;
756962306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_DOWN_SPEED, data);
757062306a36Sopenharmony_ci		tp->ups_info._10m_ckdiv = true;
757162306a36Sopenharmony_ci		tp->ups_info.eee_plloff_100 = false;
757262306a36Sopenharmony_ci		tp->ups_info.eee_plloff_giga = false;
757362306a36Sopenharmony_ci
757462306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_POWER_CFG);
757562306a36Sopenharmony_ci		data &= ~EEE_CLKDIV_EN;
757662306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_POWER_CFG, data);
757762306a36Sopenharmony_ci		tp->ups_info.eee_ckdiv = false;
757862306a36Sopenharmony_ci
757962306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_SYSCLK_CFG, 0);
758062306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_SYSCLK_CFG, sysclk_div_expo(5));
758162306a36Sopenharmony_ci		tp->ups_info._250m_ckdiv = false;
758262306a36Sopenharmony_ci
758362306a36Sopenharmony_ci		rtl_phy_patch_request(tp, false, true);
758462306a36Sopenharmony_ci
758562306a36Sopenharmony_ci		/* enable ADC Ibias Cal */
758662306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xd068);
758762306a36Sopenharmony_ci		data |= BIT(13);
758862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xd068, data);
758962306a36Sopenharmony_ci
759062306a36Sopenharmony_ci		/* enable Thermal Sensor */
759162306a36Sopenharmony_ci		data = sram_read(tp, 0x81a2);
759262306a36Sopenharmony_ci		data &= ~BIT(8);
759362306a36Sopenharmony_ci		sram_write(tp, 0x81a2, data);
759462306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb54c);
759562306a36Sopenharmony_ci		data &= ~0xff00;
759662306a36Sopenharmony_ci		data |= 0xdb00;
759762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb54c, data);
759862306a36Sopenharmony_ci
759962306a36Sopenharmony_ci		/* Nway 2.5G Lite */
760062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa454);
760162306a36Sopenharmony_ci		data &= ~BIT(0);
760262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa454, data);
760362306a36Sopenharmony_ci
760462306a36Sopenharmony_ci		/* CS DSP solution */
760562306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_10GBT_CTRL);
760662306a36Sopenharmony_ci		data |= RTL_ADV2_5G_F_R;
760762306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_10GBT_CTRL, data);
760862306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad4e);
760962306a36Sopenharmony_ci		data &= ~BIT(4);
761062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad4e, data);
761162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa86a);
761262306a36Sopenharmony_ci		data &= ~BIT(0);
761362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa86a, data);
761462306a36Sopenharmony_ci
761562306a36Sopenharmony_ci		/* MDI SWAP */
761662306a36Sopenharmony_ci		if ((ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG) & MID_REVERSE) &&
761762306a36Sopenharmony_ci		    (ocp_reg_read(tp, 0xd068) & BIT(1))) {
761862306a36Sopenharmony_ci			u16 swap_a, swap_b;
761962306a36Sopenharmony_ci
762062306a36Sopenharmony_ci			data = ocp_reg_read(tp, 0xd068);
762162306a36Sopenharmony_ci			data &= ~0x1f;
762262306a36Sopenharmony_ci			data |= 0x1; /* p0 */
762362306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
762462306a36Sopenharmony_ci			swap_a = ocp_reg_read(tp, 0xd06a);
762562306a36Sopenharmony_ci			data &= ~0x18;
762662306a36Sopenharmony_ci			data |= 0x18; /* p3 */
762762306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
762862306a36Sopenharmony_ci			swap_b = ocp_reg_read(tp, 0xd06a);
762962306a36Sopenharmony_ci			data &= ~0x18; /* p0 */
763062306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
763162306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd06a,
763262306a36Sopenharmony_ci				      (swap_a & ~0x7ff) | (swap_b & 0x7ff));
763362306a36Sopenharmony_ci			data |= 0x18; /* p3 */
763462306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
763562306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd06a,
763662306a36Sopenharmony_ci				      (swap_b & ~0x7ff) | (swap_a & 0x7ff));
763762306a36Sopenharmony_ci			data &= ~0x18;
763862306a36Sopenharmony_ci			data |= 0x08; /* p1 */
763962306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
764062306a36Sopenharmony_ci			swap_a = ocp_reg_read(tp, 0xd06a);
764162306a36Sopenharmony_ci			data &= ~0x18;
764262306a36Sopenharmony_ci			data |= 0x10; /* p2 */
764362306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
764462306a36Sopenharmony_ci			swap_b = ocp_reg_read(tp, 0xd06a);
764562306a36Sopenharmony_ci			data &= ~0x18;
764662306a36Sopenharmony_ci			data |= 0x08; /* p1 */
764762306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
764862306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd06a,
764962306a36Sopenharmony_ci				      (swap_a & ~0x7ff) | (swap_b & 0x7ff));
765062306a36Sopenharmony_ci			data &= ~0x18;
765162306a36Sopenharmony_ci			data |= 0x10; /* p2 */
765262306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd068, data);
765362306a36Sopenharmony_ci			ocp_reg_write(tp, 0xd06a,
765462306a36Sopenharmony_ci				      (swap_b & ~0x7ff) | (swap_a & 0x7ff));
765562306a36Sopenharmony_ci			swap_a = ocp_reg_read(tp, 0xbd5a);
765662306a36Sopenharmony_ci			swap_b = ocp_reg_read(tp, 0xbd5c);
765762306a36Sopenharmony_ci			ocp_reg_write(tp, 0xbd5a, (swap_a & ~0x1f1f) |
765862306a36Sopenharmony_ci				      ((swap_b & 0x1f) << 8) |
765962306a36Sopenharmony_ci				      ((swap_b >> 8) & 0x1f));
766062306a36Sopenharmony_ci			ocp_reg_write(tp, 0xbd5c, (swap_b & ~0x1f1f) |
766162306a36Sopenharmony_ci				      ((swap_a & 0x1f) << 8) |
766262306a36Sopenharmony_ci				      ((swap_a >> 8) & 0x1f));
766362306a36Sopenharmony_ci			swap_a = ocp_reg_read(tp, 0xbc18);
766462306a36Sopenharmony_ci			swap_b = ocp_reg_read(tp, 0xbc1a);
766562306a36Sopenharmony_ci			ocp_reg_write(tp, 0xbc18, (swap_a & ~0x1f1f) |
766662306a36Sopenharmony_ci				      ((swap_b & 0x1f) << 8) |
766762306a36Sopenharmony_ci				      ((swap_b >> 8) & 0x1f));
766862306a36Sopenharmony_ci			ocp_reg_write(tp, 0xbc1a, (swap_b & ~0x1f1f) |
766962306a36Sopenharmony_ci				      ((swap_a & 0x1f) << 8) |
767062306a36Sopenharmony_ci				      ((swap_a >> 8) & 0x1f));
767162306a36Sopenharmony_ci		}
767262306a36Sopenharmony_ci
767362306a36Sopenharmony_ci		/* Notify the MAC when the speed is changed to force mode. */
767462306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_INTR_EN);
767562306a36Sopenharmony_ci		data |= INTR_SPEED_FORCE;
767662306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_INTR_EN, data);
767762306a36Sopenharmony_ci		break;
767862306a36Sopenharmony_ci	default:
767962306a36Sopenharmony_ci		break;
768062306a36Sopenharmony_ci	}
768162306a36Sopenharmony_ci
768262306a36Sopenharmony_ci	rtl_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
768362306a36Sopenharmony_ci
768462306a36Sopenharmony_ci	data = ocp_reg_read(tp, 0xa428);
768562306a36Sopenharmony_ci	data &= ~BIT(9);
768662306a36Sopenharmony_ci	ocp_reg_write(tp, 0xa428, data);
768762306a36Sopenharmony_ci	data = ocp_reg_read(tp, 0xa5ea);
768862306a36Sopenharmony_ci	data &= ~BIT(0);
768962306a36Sopenharmony_ci	ocp_reg_write(tp, 0xa5ea, data);
769062306a36Sopenharmony_ci	tp->ups_info.lite_mode = 0;
769162306a36Sopenharmony_ci
769262306a36Sopenharmony_ci	if (tp->eee_en)
769362306a36Sopenharmony_ci		rtl_eee_enable(tp, true);
769462306a36Sopenharmony_ci
769562306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
769662306a36Sopenharmony_ci	r8152b_enable_fc(tp);
769762306a36Sopenharmony_ci	r8153_u2p3en(tp, true);
769862306a36Sopenharmony_ci
769962306a36Sopenharmony_ci	set_bit(PHY_RESET, &tp->flags);
770062306a36Sopenharmony_ci}
770162306a36Sopenharmony_ci
770262306a36Sopenharmony_cistatic void r8156b_hw_phy_cfg(struct r8152 *tp)
770362306a36Sopenharmony_ci{
770462306a36Sopenharmony_ci	u32 ocp_data;
770562306a36Sopenharmony_ci	u16 data;
770662306a36Sopenharmony_ci
770762306a36Sopenharmony_ci	switch (tp->version) {
770862306a36Sopenharmony_ci	case RTL_VER_12:
770962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf86, 0x9000);
771062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xc402);
771162306a36Sopenharmony_ci		data |= BIT(10);
771262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xc402, data);
771362306a36Sopenharmony_ci		data &= ~BIT(10);
771462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xc402, data);
771562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbd86, 0x1010);
771662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbd88, 0x1010);
771762306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbd4e);
771862306a36Sopenharmony_ci		data &= ~(BIT(10) | BIT(11));
771962306a36Sopenharmony_ci		data |= BIT(11);
772062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbd4e, data);
772162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf46);
772262306a36Sopenharmony_ci		data &= ~0xf00;
772362306a36Sopenharmony_ci		data |= 0x700;
772462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf46, data);
772562306a36Sopenharmony_ci		break;
772662306a36Sopenharmony_ci	case RTL_VER_13:
772762306a36Sopenharmony_ci	case RTL_VER_15:
772862306a36Sopenharmony_ci		r8156b_wait_loading_flash(tp);
772962306a36Sopenharmony_ci		break;
773062306a36Sopenharmony_ci	default:
773162306a36Sopenharmony_ci		break;
773262306a36Sopenharmony_ci	}
773362306a36Sopenharmony_ci
773462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
773562306a36Sopenharmony_ci	if (ocp_data & PCUT_STATUS) {
773662306a36Sopenharmony_ci		ocp_data &= ~PCUT_STATUS;
773762306a36Sopenharmony_ci		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
773862306a36Sopenharmony_ci	}
773962306a36Sopenharmony_ci
774062306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
774162306a36Sopenharmony_ci	switch (data) {
774262306a36Sopenharmony_ci	case PHY_STAT_EXT_INIT:
774362306a36Sopenharmony_ci		rtl8152_apply_firmware(tp, true);
774462306a36Sopenharmony_ci
774562306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa466);
774662306a36Sopenharmony_ci		data &= ~BIT(0);
774762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa466, data);
774862306a36Sopenharmony_ci
774962306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa468);
775062306a36Sopenharmony_ci		data &= ~(BIT(3) | BIT(1));
775162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa468, data);
775262306a36Sopenharmony_ci		break;
775362306a36Sopenharmony_ci	case PHY_STAT_LAN_ON:
775462306a36Sopenharmony_ci	case PHY_STAT_PWRDN:
775562306a36Sopenharmony_ci	default:
775662306a36Sopenharmony_ci		rtl8152_apply_firmware(tp, false);
775762306a36Sopenharmony_ci		break;
775862306a36Sopenharmony_ci	}
775962306a36Sopenharmony_ci
776062306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
776162306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
776262306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
776362306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
776462306a36Sopenharmony_ci	}
776562306a36Sopenharmony_ci
776662306a36Sopenharmony_ci	/* disable ALDPS before updating the PHY parameters */
776762306a36Sopenharmony_ci	r8153_aldps_en(tp, false);
776862306a36Sopenharmony_ci
776962306a36Sopenharmony_ci	/* disable EEE before updating the PHY parameters */
777062306a36Sopenharmony_ci	rtl_eee_enable(tp, false);
777162306a36Sopenharmony_ci
777262306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
777362306a36Sopenharmony_ci	WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
777462306a36Sopenharmony_ci
777562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
777662306a36Sopenharmony_ci	ocp_data |= PFM_PWM_SWITCH;
777762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
777862306a36Sopenharmony_ci
777962306a36Sopenharmony_ci	switch (tp->version) {
778062306a36Sopenharmony_ci	case RTL_VER_12:
778162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbc08);
778262306a36Sopenharmony_ci		data |= BIT(3) | BIT(2);
778362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbc08, data);
778462306a36Sopenharmony_ci
778562306a36Sopenharmony_ci		data = sram_read(tp, 0x8fff);
778662306a36Sopenharmony_ci		data &= ~0xff00;
778762306a36Sopenharmony_ci		data |= 0x0400;
778862306a36Sopenharmony_ci		sram_write(tp, 0x8fff, data);
778962306a36Sopenharmony_ci
779062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xacda);
779162306a36Sopenharmony_ci		data |= 0xff00;
779262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xacda, data);
779362306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xacde);
779462306a36Sopenharmony_ci		data |= 0xf000;
779562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xacde, data);
779662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac8c, 0x0ffc);
779762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac46, 0xb7b4);
779862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac50, 0x0fbc);
779962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac3c, 0x9240);
780062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac4e, 0x0db4);
780162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xacc6, 0x0707);
780262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xacc8, 0xa0d3);
780362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad08, 0x0007);
780462306a36Sopenharmony_ci
780562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8560);
780662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x19cc);
780762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8562);
780862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x19cc);
780962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8564);
781062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x19cc);
781162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8566);
781262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x147d);
781362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8568);
781462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x147d);
781562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x856a);
781662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x147d);
781762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8ffe);
781862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0907);
781962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x80d6);
782062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x2801);
782162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x80f2);
782262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x2801);
782362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x80f4);
782462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x6077);
782562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb506, 0x01e7);
782662306a36Sopenharmony_ci
782762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8013);
782862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0700);
782962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fb9);
783062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x2801);
783162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fba);
783262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0100);
783362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fbc);
783462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x1900);
783562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fbe);
783662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xe100);
783762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fc0);
783862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0800);
783962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fc2);
784062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xe500);
784162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fc4);
784262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0f00);
784362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fc6);
784462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xf100);
784562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fc8);
784662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0400);
784762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fca);
784862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xf300);
784962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fcc);
785062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xfd00);
785162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fce);
785262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xff00);
785362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fd0);
785462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xfb00);
785562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fd2);
785662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0100);
785762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fd4);
785862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xf400);
785962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fd6);
786062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xff00);
786162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8fd8);
786262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xf600);
786362306a36Sopenharmony_ci
786462306a36Sopenharmony_ci		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_USB_CFG);
786562306a36Sopenharmony_ci		ocp_data |= EN_XG_LIP | EN_G_LIP;
786662306a36Sopenharmony_ci		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_USB_CFG, ocp_data);
786762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x813d);
786862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x390e);
786962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x814f);
787062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x790e);
787162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x80b0);
787262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0f31);
787362306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf4c);
787462306a36Sopenharmony_ci		data |= BIT(1);
787562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf4c, data);
787662306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbcca);
787762306a36Sopenharmony_ci		data |= BIT(9) | BIT(8);
787862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbcca, data);
787962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8141);
788062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x320e);
788162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8153);
788262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x720e);
788362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8529);
788462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x050e);
788562306a36Sopenharmony_ci		data = ocp_reg_read(tp, OCP_EEE_CFG);
788662306a36Sopenharmony_ci		data &= ~CTAP_SHORT_EN;
788762306a36Sopenharmony_ci		ocp_reg_write(tp, OCP_EEE_CFG, data);
788862306a36Sopenharmony_ci
788962306a36Sopenharmony_ci		sram_write(tp, 0x816c, 0xc4a0);
789062306a36Sopenharmony_ci		sram_write(tp, 0x8170, 0xc4a0);
789162306a36Sopenharmony_ci		sram_write(tp, 0x8174, 0x04a0);
789262306a36Sopenharmony_ci		sram_write(tp, 0x8178, 0x04a0);
789362306a36Sopenharmony_ci		sram_write(tp, 0x817c, 0x0719);
789462306a36Sopenharmony_ci		sram_write(tp, 0x8ff4, 0x0400);
789562306a36Sopenharmony_ci		sram_write(tp, 0x8ff1, 0x0404);
789662306a36Sopenharmony_ci
789762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf4a, 0x001b);
789862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8033);
789962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x7c13);
790062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8037);
790162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x7c13);
790262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x803b);
790362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0xfc32);
790462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x803f);
790562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x7c13);
790662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8043);
790762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x7c13);
790862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8047);
790962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x7c13);
791062306a36Sopenharmony_ci
791162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8145);
791262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x370e);
791362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8157);
791462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x770e);
791562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8169);
791662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x0d0a);
791762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x817b);
791862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x1d0a);
791962306a36Sopenharmony_ci
792062306a36Sopenharmony_ci		data = sram_read(tp, 0x8217);
792162306a36Sopenharmony_ci		data &= ~0xff00;
792262306a36Sopenharmony_ci		data |= 0x5000;
792362306a36Sopenharmony_ci		sram_write(tp, 0x8217, data);
792462306a36Sopenharmony_ci		data = sram_read(tp, 0x821a);
792562306a36Sopenharmony_ci		data &= ~0xff00;
792662306a36Sopenharmony_ci		data |= 0x5000;
792762306a36Sopenharmony_ci		sram_write(tp, 0x821a, data);
792862306a36Sopenharmony_ci		sram_write(tp, 0x80da, 0x0403);
792962306a36Sopenharmony_ci		data = sram_read(tp, 0x80dc);
793062306a36Sopenharmony_ci		data &= ~0xff00;
793162306a36Sopenharmony_ci		data |= 0x1000;
793262306a36Sopenharmony_ci		sram_write(tp, 0x80dc, data);
793362306a36Sopenharmony_ci		sram_write(tp, 0x80b3, 0x0384);
793462306a36Sopenharmony_ci		sram_write(tp, 0x80b7, 0x2007);
793562306a36Sopenharmony_ci		data = sram_read(tp, 0x80ba);
793662306a36Sopenharmony_ci		data &= ~0xff00;
793762306a36Sopenharmony_ci		data |= 0x6c00;
793862306a36Sopenharmony_ci		sram_write(tp, 0x80ba, data);
793962306a36Sopenharmony_ci		sram_write(tp, 0x80b5, 0xf009);
794062306a36Sopenharmony_ci		data = sram_read(tp, 0x80bd);
794162306a36Sopenharmony_ci		data &= ~0xff00;
794262306a36Sopenharmony_ci		data |= 0x9f00;
794362306a36Sopenharmony_ci		sram_write(tp, 0x80bd, data);
794462306a36Sopenharmony_ci		sram_write(tp, 0x80c7, 0xf083);
794562306a36Sopenharmony_ci		sram_write(tp, 0x80dd, 0x03f0);
794662306a36Sopenharmony_ci		data = sram_read(tp, 0x80df);
794762306a36Sopenharmony_ci		data &= ~0xff00;
794862306a36Sopenharmony_ci		data |= 0x1000;
794962306a36Sopenharmony_ci		sram_write(tp, 0x80df, data);
795062306a36Sopenharmony_ci		sram_write(tp, 0x80cb, 0x2007);
795162306a36Sopenharmony_ci		data = sram_read(tp, 0x80ce);
795262306a36Sopenharmony_ci		data &= ~0xff00;
795362306a36Sopenharmony_ci		data |= 0x6c00;
795462306a36Sopenharmony_ci		sram_write(tp, 0x80ce, data);
795562306a36Sopenharmony_ci		sram_write(tp, 0x80c9, 0x8009);
795662306a36Sopenharmony_ci		data = sram_read(tp, 0x80d1);
795762306a36Sopenharmony_ci		data &= ~0xff00;
795862306a36Sopenharmony_ci		data |= 0x8000;
795962306a36Sopenharmony_ci		sram_write(tp, 0x80d1, data);
796062306a36Sopenharmony_ci		sram_write(tp, 0x80a3, 0x200a);
796162306a36Sopenharmony_ci		sram_write(tp, 0x80a5, 0xf0ad);
796262306a36Sopenharmony_ci		sram_write(tp, 0x809f, 0x6073);
796362306a36Sopenharmony_ci		sram_write(tp, 0x80a1, 0x000b);
796462306a36Sopenharmony_ci		data = sram_read(tp, 0x80a9);
796562306a36Sopenharmony_ci		data &= ~0xff00;
796662306a36Sopenharmony_ci		data |= 0xc000;
796762306a36Sopenharmony_ci		sram_write(tp, 0x80a9, data);
796862306a36Sopenharmony_ci
796962306a36Sopenharmony_ci		if (rtl_phy_patch_request(tp, true, true))
797062306a36Sopenharmony_ci			return;
797162306a36Sopenharmony_ci
797262306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb896);
797362306a36Sopenharmony_ci		data &= ~BIT(0);
797462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb896, data);
797562306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb892);
797662306a36Sopenharmony_ci		data &= ~0xff00;
797762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb892, data);
797862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc23e);
797962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x0000);
798062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc240);
798162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x0103);
798262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc242);
798362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x0507);
798462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc244);
798562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x090b);
798662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc246);
798762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x0c0e);
798862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc248);
798962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x1012);
799062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb88e, 0xc24a);
799162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb890, 0x1416);
799262306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb896);
799362306a36Sopenharmony_ci		data |= BIT(0);
799462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb896, data);
799562306a36Sopenharmony_ci
799662306a36Sopenharmony_ci		rtl_phy_patch_request(tp, false, true);
799762306a36Sopenharmony_ci
799862306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa86a);
799962306a36Sopenharmony_ci		data |= BIT(0);
800062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa86a, data);
800162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa6f0);
800262306a36Sopenharmony_ci		data |= BIT(0);
800362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa6f0, data);
800462306a36Sopenharmony_ci
800562306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbfa0, 0xd70d);
800662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbfa2, 0x4100);
800762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbfa4, 0xe868);
800862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbfa6, 0xdc59);
800962306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb54c, 0x3c18);
801062306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbfa4);
801162306a36Sopenharmony_ci		data &= ~BIT(5);
801262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbfa4, data);
801362306a36Sopenharmony_ci		data = sram_read(tp, 0x817d);
801462306a36Sopenharmony_ci		data |= BIT(12);
801562306a36Sopenharmony_ci		sram_write(tp, 0x817d, data);
801662306a36Sopenharmony_ci		break;
801762306a36Sopenharmony_ci	case RTL_VER_13:
801862306a36Sopenharmony_ci		/* 2.5G INRX */
801962306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xac46);
802062306a36Sopenharmony_ci		data &= ~0x00f0;
802162306a36Sopenharmony_ci		data |= 0x0090;
802262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xac46, data);
802362306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xad30);
802462306a36Sopenharmony_ci		data &= ~0x0003;
802562306a36Sopenharmony_ci		data |= 0x0001;
802662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xad30, data);
802762306a36Sopenharmony_ci		fallthrough;
802862306a36Sopenharmony_ci	case RTL_VER_15:
802962306a36Sopenharmony_ci		/* EEE parameter */
803062306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x80f5);
803162306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x760e);
803262306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8107);
803362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, 0x360e);
803462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87c, 0x8551);
803562306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xb87e);
803662306a36Sopenharmony_ci		data &= ~0xff00;
803762306a36Sopenharmony_ci		data |= 0x0800;
803862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xb87e, data);
803962306a36Sopenharmony_ci
804062306a36Sopenharmony_ci		/* ADC_PGA parameter */
804162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf00);
804262306a36Sopenharmony_ci		data &= ~0xe000;
804362306a36Sopenharmony_ci		data |= 0xa000;
804462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf00, data);
804562306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf46);
804662306a36Sopenharmony_ci		data &= ~0x0f00;
804762306a36Sopenharmony_ci		data |= 0x0300;
804862306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf46, data);
804962306a36Sopenharmony_ci
805062306a36Sopenharmony_ci		/* Green Table-PGA, 1G full viterbi */
805162306a36Sopenharmony_ci		sram_write(tp, 0x8044, 0x2417);
805262306a36Sopenharmony_ci		sram_write(tp, 0x804a, 0x2417);
805362306a36Sopenharmony_ci		sram_write(tp, 0x8050, 0x2417);
805462306a36Sopenharmony_ci		sram_write(tp, 0x8056, 0x2417);
805562306a36Sopenharmony_ci		sram_write(tp, 0x805c, 0x2417);
805662306a36Sopenharmony_ci		sram_write(tp, 0x8062, 0x2417);
805762306a36Sopenharmony_ci		sram_write(tp, 0x8068, 0x2417);
805862306a36Sopenharmony_ci		sram_write(tp, 0x806e, 0x2417);
805962306a36Sopenharmony_ci		sram_write(tp, 0x8074, 0x2417);
806062306a36Sopenharmony_ci		sram_write(tp, 0x807a, 0x2417);
806162306a36Sopenharmony_ci
806262306a36Sopenharmony_ci		/* XG PLL */
806362306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xbf84);
806462306a36Sopenharmony_ci		data &= ~0xe000;
806562306a36Sopenharmony_ci		data |= 0xa000;
806662306a36Sopenharmony_ci		ocp_reg_write(tp, 0xbf84, data);
806762306a36Sopenharmony_ci		break;
806862306a36Sopenharmony_ci	default:
806962306a36Sopenharmony_ci		break;
807062306a36Sopenharmony_ci	}
807162306a36Sopenharmony_ci
807262306a36Sopenharmony_ci	/* Notify the MAC when the speed is changed to force mode. */
807362306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_INTR_EN);
807462306a36Sopenharmony_ci	data |= INTR_SPEED_FORCE;
807562306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_INTR_EN, data);
807662306a36Sopenharmony_ci
807762306a36Sopenharmony_ci	if (rtl_phy_patch_request(tp, true, true))
807862306a36Sopenharmony_ci		return;
807962306a36Sopenharmony_ci
808062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
808162306a36Sopenharmony_ci	ocp_data |= EEE_SPDWN_EN;
808262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
808362306a36Sopenharmony_ci
808462306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_DOWN_SPEED);
808562306a36Sopenharmony_ci	data &= ~(EN_EEE_100 | EN_EEE_1000);
808662306a36Sopenharmony_ci	data |= EN_10M_CLKDIV;
808762306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_DOWN_SPEED, data);
808862306a36Sopenharmony_ci	tp->ups_info._10m_ckdiv = true;
808962306a36Sopenharmony_ci	tp->ups_info.eee_plloff_100 = false;
809062306a36Sopenharmony_ci	tp->ups_info.eee_plloff_giga = false;
809162306a36Sopenharmony_ci
809262306a36Sopenharmony_ci	data = ocp_reg_read(tp, OCP_POWER_CFG);
809362306a36Sopenharmony_ci	data &= ~EEE_CLKDIV_EN;
809462306a36Sopenharmony_ci	ocp_reg_write(tp, OCP_POWER_CFG, data);
809562306a36Sopenharmony_ci	tp->ups_info.eee_ckdiv = false;
809662306a36Sopenharmony_ci
809762306a36Sopenharmony_ci	rtl_phy_patch_request(tp, false, true);
809862306a36Sopenharmony_ci
809962306a36Sopenharmony_ci	rtl_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
810062306a36Sopenharmony_ci
810162306a36Sopenharmony_ci	data = ocp_reg_read(tp, 0xa428);
810262306a36Sopenharmony_ci	data &= ~BIT(9);
810362306a36Sopenharmony_ci	ocp_reg_write(tp, 0xa428, data);
810462306a36Sopenharmony_ci	data = ocp_reg_read(tp, 0xa5ea);
810562306a36Sopenharmony_ci	data &= ~BIT(0);
810662306a36Sopenharmony_ci	ocp_reg_write(tp, 0xa5ea, data);
810762306a36Sopenharmony_ci	tp->ups_info.lite_mode = 0;
810862306a36Sopenharmony_ci
810962306a36Sopenharmony_ci	if (tp->eee_en)
811062306a36Sopenharmony_ci		rtl_eee_enable(tp, true);
811162306a36Sopenharmony_ci
811262306a36Sopenharmony_ci	r8153_aldps_en(tp, true);
811362306a36Sopenharmony_ci	r8152b_enable_fc(tp);
811462306a36Sopenharmony_ci	r8153_u2p3en(tp, true);
811562306a36Sopenharmony_ci
811662306a36Sopenharmony_ci	set_bit(PHY_RESET, &tp->flags);
811762306a36Sopenharmony_ci}
811862306a36Sopenharmony_ci
811962306a36Sopenharmony_cistatic void r8156_init(struct r8152 *tp)
812062306a36Sopenharmony_ci{
812162306a36Sopenharmony_ci	u32 ocp_data;
812262306a36Sopenharmony_ci	u16 data;
812362306a36Sopenharmony_ci	int i;
812462306a36Sopenharmony_ci
812562306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
812662306a36Sopenharmony_ci		return;
812762306a36Sopenharmony_ci
812862306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_ECM_OP);
812962306a36Sopenharmony_ci	ocp_data &= ~EN_ALL_SPEED;
813062306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_ECM_OP, ocp_data);
813162306a36Sopenharmony_ci
813262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, 0);
813362306a36Sopenharmony_ci
813462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_ECM_OPTION);
813562306a36Sopenharmony_ci	ocp_data |= BYPASS_MAC_RESET;
813662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_ECM_OPTION, ocp_data);
813762306a36Sopenharmony_ci
813862306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
813962306a36Sopenharmony_ci
814062306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
814162306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
814262306a36Sopenharmony_ci		    AUTOLOAD_DONE)
814362306a36Sopenharmony_ci			break;
814462306a36Sopenharmony_ci
814562306a36Sopenharmony_ci		msleep(20);
814662306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
814762306a36Sopenharmony_ci			return;
814862306a36Sopenharmony_ci	}
814962306a36Sopenharmony_ci
815062306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
815162306a36Sopenharmony_ci	if (data == PHY_STAT_EXT_INIT) {
815262306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa468);
815362306a36Sopenharmony_ci		data &= ~(BIT(3) | BIT(1));
815462306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa468, data);
815562306a36Sopenharmony_ci	}
815662306a36Sopenharmony_ci
815762306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
815862306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
815962306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
816062306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
816162306a36Sopenharmony_ci	}
816262306a36Sopenharmony_ci
816362306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
816462306a36Sopenharmony_ci	WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
816562306a36Sopenharmony_ci
816662306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
816762306a36Sopenharmony_ci
816862306a36Sopenharmony_ci	/* MSC timer = 0xfff * 8ms = 32760 ms */
816962306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
817062306a36Sopenharmony_ci
817162306a36Sopenharmony_ci	/* U1/U2/L1 idle timer. 500 us */
817262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
817362306a36Sopenharmony_ci
817462306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
817562306a36Sopenharmony_ci	r8156_ups_en(tp, false);
817662306a36Sopenharmony_ci	r8153_queue_wake(tp, false);
817762306a36Sopenharmony_ci	rtl_runtime_suspend_enable(tp, false);
817862306a36Sopenharmony_ci
817962306a36Sopenharmony_ci	if (tp->udev->speed >= USB_SPEED_SUPER)
818062306a36Sopenharmony_ci		r8153b_u1u2en(tp, true);
818162306a36Sopenharmony_ci
818262306a36Sopenharmony_ci	usb_enable_lpm(tp->udev);
818362306a36Sopenharmony_ci
818462306a36Sopenharmony_ci	r8156_mac_clk_spd(tp, true);
818562306a36Sopenharmony_ci
818662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
818762306a36Sopenharmony_ci	ocp_data &= ~PLA_MCU_SPDWN_EN;
818862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
818962306a36Sopenharmony_ci
819062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
819162306a36Sopenharmony_ci	if (rtl8152_get_speed(tp) & LINK_STATUS)
819262306a36Sopenharmony_ci		ocp_data |= CUR_LINK_OK;
819362306a36Sopenharmony_ci	else
819462306a36Sopenharmony_ci		ocp_data &= ~CUR_LINK_OK;
819562306a36Sopenharmony_ci	ocp_data |= POLL_LINK_CHG;
819662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
819762306a36Sopenharmony_ci
819862306a36Sopenharmony_ci	set_bit(GREEN_ETHERNET, &tp->flags);
819962306a36Sopenharmony_ci
820062306a36Sopenharmony_ci	/* rx aggregation */
820162306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
820262306a36Sopenharmony_ci	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
820362306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
820462306a36Sopenharmony_ci
820562306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_BMU_CONFIG);
820662306a36Sopenharmony_ci	ocp_data |= ACT_ODMA;
820762306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ocp_data);
820862306a36Sopenharmony_ci
820962306a36Sopenharmony_ci	r8156_mdio_force_mode(tp);
821062306a36Sopenharmony_ci	rtl_tally_reset(tp);
821162306a36Sopenharmony_ci
821262306a36Sopenharmony_ci	tp->coalesce = 15000;	/* 15 us */
821362306a36Sopenharmony_ci}
821462306a36Sopenharmony_ci
821562306a36Sopenharmony_cistatic void r8156b_init(struct r8152 *tp)
821662306a36Sopenharmony_ci{
821762306a36Sopenharmony_ci	u32 ocp_data;
821862306a36Sopenharmony_ci	u16 data;
821962306a36Sopenharmony_ci	int i;
822062306a36Sopenharmony_ci
822162306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
822262306a36Sopenharmony_ci		return;
822362306a36Sopenharmony_ci
822462306a36Sopenharmony_ci	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_ECM_OP);
822562306a36Sopenharmony_ci	ocp_data &= ~EN_ALL_SPEED;
822662306a36Sopenharmony_ci	ocp_write_byte(tp, MCU_TYPE_USB, USB_ECM_OP, ocp_data);
822762306a36Sopenharmony_ci
822862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, 0);
822962306a36Sopenharmony_ci
823062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_ECM_OPTION);
823162306a36Sopenharmony_ci	ocp_data |= BYPASS_MAC_RESET;
823262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_ECM_OPTION, ocp_data);
823362306a36Sopenharmony_ci
823462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
823562306a36Sopenharmony_ci	ocp_data |= RX_DETECT8;
823662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
823762306a36Sopenharmony_ci
823862306a36Sopenharmony_ci	r8153b_u1u2en(tp, false);
823962306a36Sopenharmony_ci
824062306a36Sopenharmony_ci	switch (tp->version) {
824162306a36Sopenharmony_ci	case RTL_VER_13:
824262306a36Sopenharmony_ci	case RTL_VER_15:
824362306a36Sopenharmony_ci		r8156b_wait_loading_flash(tp);
824462306a36Sopenharmony_ci		break;
824562306a36Sopenharmony_ci	default:
824662306a36Sopenharmony_ci		break;
824762306a36Sopenharmony_ci	}
824862306a36Sopenharmony_ci
824962306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
825062306a36Sopenharmony_ci		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
825162306a36Sopenharmony_ci		    AUTOLOAD_DONE)
825262306a36Sopenharmony_ci			break;
825362306a36Sopenharmony_ci
825462306a36Sopenharmony_ci		msleep(20);
825562306a36Sopenharmony_ci		if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
825662306a36Sopenharmony_ci			return;
825762306a36Sopenharmony_ci	}
825862306a36Sopenharmony_ci
825962306a36Sopenharmony_ci	data = r8153_phy_status(tp, 0);
826062306a36Sopenharmony_ci	if (data == PHY_STAT_EXT_INIT) {
826162306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa468);
826262306a36Sopenharmony_ci		data &= ~(BIT(3) | BIT(1));
826362306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa468, data);
826462306a36Sopenharmony_ci
826562306a36Sopenharmony_ci		data = ocp_reg_read(tp, 0xa466);
826662306a36Sopenharmony_ci		data &= ~BIT(0);
826762306a36Sopenharmony_ci		ocp_reg_write(tp, 0xa466, data);
826862306a36Sopenharmony_ci	}
826962306a36Sopenharmony_ci
827062306a36Sopenharmony_ci	data = r8152_mdio_read(tp, MII_BMCR);
827162306a36Sopenharmony_ci	if (data & BMCR_PDOWN) {
827262306a36Sopenharmony_ci		data &= ~BMCR_PDOWN;
827362306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_BMCR, data);
827462306a36Sopenharmony_ci	}
827562306a36Sopenharmony_ci
827662306a36Sopenharmony_ci	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
827762306a36Sopenharmony_ci
827862306a36Sopenharmony_ci	r8153_u2p3en(tp, false);
827962306a36Sopenharmony_ci
828062306a36Sopenharmony_ci	/* MSC timer = 0xfff * 8ms = 32760 ms */
828162306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
828262306a36Sopenharmony_ci
828362306a36Sopenharmony_ci	/* U1/U2/L1 idle timer. 500 us */
828462306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
828562306a36Sopenharmony_ci
828662306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
828762306a36Sopenharmony_ci	r8156_ups_en(tp, false);
828862306a36Sopenharmony_ci	r8153_queue_wake(tp, false);
828962306a36Sopenharmony_ci	rtl_runtime_suspend_enable(tp, false);
829062306a36Sopenharmony_ci
829162306a36Sopenharmony_ci	if (tp->udev->speed >= USB_SPEED_SUPER)
829262306a36Sopenharmony_ci		r8153b_u1u2en(tp, true);
829362306a36Sopenharmony_ci
829462306a36Sopenharmony_ci	usb_enable_lpm(tp->udev);
829562306a36Sopenharmony_ci
829662306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RCR);
829762306a36Sopenharmony_ci	ocp_data &= ~SLOT_EN;
829862306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
829962306a36Sopenharmony_ci
830062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
830162306a36Sopenharmony_ci	ocp_data |= FLOW_CTRL_EN;
830262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
830362306a36Sopenharmony_ci
830462306a36Sopenharmony_ci	/* enable fc timer and set timer to 600 ms. */
830562306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER,
830662306a36Sopenharmony_ci		       CTRL_TIMER_EN | (600 / 8));
830762306a36Sopenharmony_ci
830862306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL);
830962306a36Sopenharmony_ci	if (!(ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL) & DACK_DET_EN))
831062306a36Sopenharmony_ci		ocp_data |= FLOW_CTRL_PATCH_2;
831162306a36Sopenharmony_ci	ocp_data &= ~AUTO_SPEEDUP;
831262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data);
831362306a36Sopenharmony_ci
831462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
831562306a36Sopenharmony_ci	ocp_data |= FC_PATCH_TASK;
831662306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
831762306a36Sopenharmony_ci
831862306a36Sopenharmony_ci	r8156_mac_clk_spd(tp, true);
831962306a36Sopenharmony_ci
832062306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
832162306a36Sopenharmony_ci	ocp_data &= ~PLA_MCU_SPDWN_EN;
832262306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
832362306a36Sopenharmony_ci
832462306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
832562306a36Sopenharmony_ci	if (rtl8152_get_speed(tp) & LINK_STATUS)
832662306a36Sopenharmony_ci		ocp_data |= CUR_LINK_OK;
832762306a36Sopenharmony_ci	else
832862306a36Sopenharmony_ci		ocp_data &= ~CUR_LINK_OK;
832962306a36Sopenharmony_ci	ocp_data |= POLL_LINK_CHG;
833062306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
833162306a36Sopenharmony_ci
833262306a36Sopenharmony_ci	set_bit(GREEN_ETHERNET, &tp->flags);
833362306a36Sopenharmony_ci
833462306a36Sopenharmony_ci	/* rx aggregation */
833562306a36Sopenharmony_ci	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
833662306a36Sopenharmony_ci	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
833762306a36Sopenharmony_ci	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
833862306a36Sopenharmony_ci
833962306a36Sopenharmony_ci	r8156_mdio_force_mode(tp);
834062306a36Sopenharmony_ci	rtl_tally_reset(tp);
834162306a36Sopenharmony_ci
834262306a36Sopenharmony_ci	tp->coalesce = 15000;	/* 15 us */
834362306a36Sopenharmony_ci}
834462306a36Sopenharmony_ci
834562306a36Sopenharmony_cistatic bool rtl_check_vendor_ok(struct usb_interface *intf)
834662306a36Sopenharmony_ci{
834762306a36Sopenharmony_ci	struct usb_host_interface *alt = intf->cur_altsetting;
834862306a36Sopenharmony_ci	struct usb_endpoint_descriptor *in, *out, *intr;
834962306a36Sopenharmony_ci
835062306a36Sopenharmony_ci	if (usb_find_common_endpoints(alt, &in, &out, &intr, NULL) < 0) {
835162306a36Sopenharmony_ci		dev_err(&intf->dev, "Expected endpoints are not found\n");
835262306a36Sopenharmony_ci		return false;
835362306a36Sopenharmony_ci	}
835462306a36Sopenharmony_ci
835562306a36Sopenharmony_ci	/* Check Rx endpoint address */
835662306a36Sopenharmony_ci	if (usb_endpoint_num(in) != 1) {
835762306a36Sopenharmony_ci		dev_err(&intf->dev, "Invalid Rx endpoint address\n");
835862306a36Sopenharmony_ci		return false;
835962306a36Sopenharmony_ci	}
836062306a36Sopenharmony_ci
836162306a36Sopenharmony_ci	/* Check Tx endpoint address */
836262306a36Sopenharmony_ci	if (usb_endpoint_num(out) != 2) {
836362306a36Sopenharmony_ci		dev_err(&intf->dev, "Invalid Tx endpoint address\n");
836462306a36Sopenharmony_ci		return false;
836562306a36Sopenharmony_ci	}
836662306a36Sopenharmony_ci
836762306a36Sopenharmony_ci	/* Check interrupt endpoint address */
836862306a36Sopenharmony_ci	if (usb_endpoint_num(intr) != 3) {
836962306a36Sopenharmony_ci		dev_err(&intf->dev, "Invalid interrupt endpoint address\n");
837062306a36Sopenharmony_ci		return false;
837162306a36Sopenharmony_ci	}
837262306a36Sopenharmony_ci
837362306a36Sopenharmony_ci	return true;
837462306a36Sopenharmony_ci}
837562306a36Sopenharmony_ci
837662306a36Sopenharmony_cistatic int rtl8152_pre_reset(struct usb_interface *intf)
837762306a36Sopenharmony_ci{
837862306a36Sopenharmony_ci	struct r8152 *tp = usb_get_intfdata(intf);
837962306a36Sopenharmony_ci	struct net_device *netdev;
838062306a36Sopenharmony_ci
838162306a36Sopenharmony_ci	rtnl_lock();
838262306a36Sopenharmony_ci
838362306a36Sopenharmony_ci	if (!tp || !test_bit(PROBED_WITH_NO_ERRORS, &tp->flags))
838462306a36Sopenharmony_ci		return 0;
838562306a36Sopenharmony_ci
838662306a36Sopenharmony_ci	netdev = tp->netdev;
838762306a36Sopenharmony_ci	if (!netif_running(netdev))
838862306a36Sopenharmony_ci		return 0;
838962306a36Sopenharmony_ci
839062306a36Sopenharmony_ci	netif_stop_queue(netdev);
839162306a36Sopenharmony_ci	tasklet_disable(&tp->tx_tl);
839262306a36Sopenharmony_ci	clear_bit(WORK_ENABLE, &tp->flags);
839362306a36Sopenharmony_ci	usb_kill_urb(tp->intr_urb);
839462306a36Sopenharmony_ci	cancel_delayed_work_sync(&tp->schedule);
839562306a36Sopenharmony_ci	napi_disable(&tp->napi);
839662306a36Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
839762306a36Sopenharmony_ci		mutex_lock(&tp->control);
839862306a36Sopenharmony_ci		set_bit(IN_PRE_RESET, &tp->flags);
839962306a36Sopenharmony_ci		tp->rtl_ops.disable(tp);
840062306a36Sopenharmony_ci		clear_bit(IN_PRE_RESET, &tp->flags);
840162306a36Sopenharmony_ci		mutex_unlock(&tp->control);
840262306a36Sopenharmony_ci	}
840362306a36Sopenharmony_ci
840462306a36Sopenharmony_ci	return 0;
840562306a36Sopenharmony_ci}
840662306a36Sopenharmony_ci
840762306a36Sopenharmony_cistatic int rtl8152_post_reset(struct usb_interface *intf)
840862306a36Sopenharmony_ci{
840962306a36Sopenharmony_ci	struct r8152 *tp = usb_get_intfdata(intf);
841062306a36Sopenharmony_ci	struct net_device *netdev;
841162306a36Sopenharmony_ci	struct sockaddr sa;
841262306a36Sopenharmony_ci
841362306a36Sopenharmony_ci	if (!tp || !test_bit(PROBED_WITH_NO_ERRORS, &tp->flags))
841462306a36Sopenharmony_ci		goto exit;
841562306a36Sopenharmony_ci
841662306a36Sopenharmony_ci	rtl_set_accessible(tp);
841762306a36Sopenharmony_ci
841862306a36Sopenharmony_ci	/* reset the MAC address in case of policy change */
841962306a36Sopenharmony_ci	if (determine_ethernet_addr(tp, &sa) >= 0)
842062306a36Sopenharmony_ci		dev_set_mac_address (tp->netdev, &sa, NULL);
842162306a36Sopenharmony_ci
842262306a36Sopenharmony_ci	netdev = tp->netdev;
842362306a36Sopenharmony_ci	if (!netif_running(netdev))
842462306a36Sopenharmony_ci		goto exit;
842562306a36Sopenharmony_ci
842662306a36Sopenharmony_ci	set_bit(WORK_ENABLE, &tp->flags);
842762306a36Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
842862306a36Sopenharmony_ci		mutex_lock(&tp->control);
842962306a36Sopenharmony_ci		tp->rtl_ops.enable(tp);
843062306a36Sopenharmony_ci		rtl_start_rx(tp);
843162306a36Sopenharmony_ci		_rtl8152_set_rx_mode(netdev);
843262306a36Sopenharmony_ci		mutex_unlock(&tp->control);
843362306a36Sopenharmony_ci	}
843462306a36Sopenharmony_ci
843562306a36Sopenharmony_ci	napi_enable(&tp->napi);
843662306a36Sopenharmony_ci	tasklet_enable(&tp->tx_tl);
843762306a36Sopenharmony_ci	netif_wake_queue(netdev);
843862306a36Sopenharmony_ci	usb_submit_urb(tp->intr_urb, GFP_KERNEL);
843962306a36Sopenharmony_ci
844062306a36Sopenharmony_ci	if (!list_empty(&tp->rx_done))
844162306a36Sopenharmony_ci		napi_schedule(&tp->napi);
844262306a36Sopenharmony_ci
844362306a36Sopenharmony_ciexit:
844462306a36Sopenharmony_ci	rtnl_unlock();
844562306a36Sopenharmony_ci	return 0;
844662306a36Sopenharmony_ci}
844762306a36Sopenharmony_ci
844862306a36Sopenharmony_cistatic bool delay_autosuspend(struct r8152 *tp)
844962306a36Sopenharmony_ci{
845062306a36Sopenharmony_ci	bool sw_linking = !!netif_carrier_ok(tp->netdev);
845162306a36Sopenharmony_ci	bool hw_linking = !!(rtl8152_get_speed(tp) & LINK_STATUS);
845262306a36Sopenharmony_ci
845362306a36Sopenharmony_ci	/* This means a linking change occurs and the driver doesn't detect it,
845462306a36Sopenharmony_ci	 * yet. If the driver has disabled tx/rx and hw is linking on, the
845562306a36Sopenharmony_ci	 * device wouldn't wake up by receiving any packet.
845662306a36Sopenharmony_ci	 */
845762306a36Sopenharmony_ci	if (work_busy(&tp->schedule.work) || sw_linking != hw_linking)
845862306a36Sopenharmony_ci		return true;
845962306a36Sopenharmony_ci
846062306a36Sopenharmony_ci	/* If the linking down is occurred by nway, the device may miss the
846162306a36Sopenharmony_ci	 * linking change event. And it wouldn't wake when linking on.
846262306a36Sopenharmony_ci	 */
846362306a36Sopenharmony_ci	if (!sw_linking && tp->rtl_ops.in_nway(tp))
846462306a36Sopenharmony_ci		return true;
846562306a36Sopenharmony_ci	else if (!skb_queue_empty(&tp->tx_queue))
846662306a36Sopenharmony_ci		return true;
846762306a36Sopenharmony_ci	else
846862306a36Sopenharmony_ci		return false;
846962306a36Sopenharmony_ci}
847062306a36Sopenharmony_ci
847162306a36Sopenharmony_cistatic int rtl8152_runtime_resume(struct r8152 *tp)
847262306a36Sopenharmony_ci{
847362306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
847462306a36Sopenharmony_ci
847562306a36Sopenharmony_ci	if (netif_running(netdev) && netdev->flags & IFF_UP) {
847662306a36Sopenharmony_ci		struct napi_struct *napi = &tp->napi;
847762306a36Sopenharmony_ci
847862306a36Sopenharmony_ci		tp->rtl_ops.autosuspend_en(tp, false);
847962306a36Sopenharmony_ci		napi_disable(napi);
848062306a36Sopenharmony_ci		set_bit(WORK_ENABLE, &tp->flags);
848162306a36Sopenharmony_ci
848262306a36Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
848362306a36Sopenharmony_ci			if (rtl8152_get_speed(tp) & LINK_STATUS) {
848462306a36Sopenharmony_ci				rtl_start_rx(tp);
848562306a36Sopenharmony_ci			} else {
848662306a36Sopenharmony_ci				netif_carrier_off(netdev);
848762306a36Sopenharmony_ci				tp->rtl_ops.disable(tp);
848862306a36Sopenharmony_ci				netif_info(tp, link, netdev, "linking down\n");
848962306a36Sopenharmony_ci			}
849062306a36Sopenharmony_ci		}
849162306a36Sopenharmony_ci
849262306a36Sopenharmony_ci		napi_enable(napi);
849362306a36Sopenharmony_ci		clear_bit(SELECTIVE_SUSPEND, &tp->flags);
849462306a36Sopenharmony_ci		smp_mb__after_atomic();
849562306a36Sopenharmony_ci
849662306a36Sopenharmony_ci		if (!list_empty(&tp->rx_done))
849762306a36Sopenharmony_ci			napi_schedule(&tp->napi);
849862306a36Sopenharmony_ci
849962306a36Sopenharmony_ci		usb_submit_urb(tp->intr_urb, GFP_NOIO);
850062306a36Sopenharmony_ci	} else {
850162306a36Sopenharmony_ci		if (netdev->flags & IFF_UP)
850262306a36Sopenharmony_ci			tp->rtl_ops.autosuspend_en(tp, false);
850362306a36Sopenharmony_ci
850462306a36Sopenharmony_ci		clear_bit(SELECTIVE_SUSPEND, &tp->flags);
850562306a36Sopenharmony_ci	}
850662306a36Sopenharmony_ci
850762306a36Sopenharmony_ci	return 0;
850862306a36Sopenharmony_ci}
850962306a36Sopenharmony_ci
851062306a36Sopenharmony_cistatic int rtl8152_system_resume(struct r8152 *tp)
851162306a36Sopenharmony_ci{
851262306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
851362306a36Sopenharmony_ci
851462306a36Sopenharmony_ci	netif_device_attach(netdev);
851562306a36Sopenharmony_ci
851662306a36Sopenharmony_ci	if (netif_running(netdev) && (netdev->flags & IFF_UP)) {
851762306a36Sopenharmony_ci		tp->rtl_ops.up(tp);
851862306a36Sopenharmony_ci		netif_carrier_off(netdev);
851962306a36Sopenharmony_ci		set_bit(WORK_ENABLE, &tp->flags);
852062306a36Sopenharmony_ci		usb_submit_urb(tp->intr_urb, GFP_NOIO);
852162306a36Sopenharmony_ci	}
852262306a36Sopenharmony_ci
852362306a36Sopenharmony_ci	return 0;
852462306a36Sopenharmony_ci}
852562306a36Sopenharmony_ci
852662306a36Sopenharmony_cistatic int rtl8152_runtime_suspend(struct r8152 *tp)
852762306a36Sopenharmony_ci{
852862306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
852962306a36Sopenharmony_ci	int ret = 0;
853062306a36Sopenharmony_ci
853162306a36Sopenharmony_ci	if (!tp->rtl_ops.autosuspend_en)
853262306a36Sopenharmony_ci		return -EBUSY;
853362306a36Sopenharmony_ci
853462306a36Sopenharmony_ci	set_bit(SELECTIVE_SUSPEND, &tp->flags);
853562306a36Sopenharmony_ci	smp_mb__after_atomic();
853662306a36Sopenharmony_ci
853762306a36Sopenharmony_ci	if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
853862306a36Sopenharmony_ci		u32 rcr = 0;
853962306a36Sopenharmony_ci
854062306a36Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
854162306a36Sopenharmony_ci			u32 ocp_data;
854262306a36Sopenharmony_ci
854362306a36Sopenharmony_ci			rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
854462306a36Sopenharmony_ci			ocp_data = rcr & ~RCR_ACPT_ALL;
854562306a36Sopenharmony_ci			ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
854662306a36Sopenharmony_ci			rxdy_gated_en(tp, true);
854762306a36Sopenharmony_ci			ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA,
854862306a36Sopenharmony_ci						 PLA_OOB_CTRL);
854962306a36Sopenharmony_ci			if (!(ocp_data & RXFIFO_EMPTY)) {
855062306a36Sopenharmony_ci				rxdy_gated_en(tp, false);
855162306a36Sopenharmony_ci				ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
855262306a36Sopenharmony_ci				clear_bit(SELECTIVE_SUSPEND, &tp->flags);
855362306a36Sopenharmony_ci				smp_mb__after_atomic();
855462306a36Sopenharmony_ci				ret = -EBUSY;
855562306a36Sopenharmony_ci				goto out1;
855662306a36Sopenharmony_ci			}
855762306a36Sopenharmony_ci		}
855862306a36Sopenharmony_ci
855962306a36Sopenharmony_ci		clear_bit(WORK_ENABLE, &tp->flags);
856062306a36Sopenharmony_ci		usb_kill_urb(tp->intr_urb);
856162306a36Sopenharmony_ci
856262306a36Sopenharmony_ci		tp->rtl_ops.autosuspend_en(tp, true);
856362306a36Sopenharmony_ci
856462306a36Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
856562306a36Sopenharmony_ci			struct napi_struct *napi = &tp->napi;
856662306a36Sopenharmony_ci
856762306a36Sopenharmony_ci			napi_disable(napi);
856862306a36Sopenharmony_ci			rtl_stop_rx(tp);
856962306a36Sopenharmony_ci			rxdy_gated_en(tp, false);
857062306a36Sopenharmony_ci			ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
857162306a36Sopenharmony_ci			napi_enable(napi);
857262306a36Sopenharmony_ci		}
857362306a36Sopenharmony_ci
857462306a36Sopenharmony_ci		if (delay_autosuspend(tp)) {
857562306a36Sopenharmony_ci			rtl8152_runtime_resume(tp);
857662306a36Sopenharmony_ci			ret = -EBUSY;
857762306a36Sopenharmony_ci		}
857862306a36Sopenharmony_ci	}
857962306a36Sopenharmony_ci
858062306a36Sopenharmony_ciout1:
858162306a36Sopenharmony_ci	return ret;
858262306a36Sopenharmony_ci}
858362306a36Sopenharmony_ci
858462306a36Sopenharmony_cistatic int rtl8152_system_suspend(struct r8152 *tp)
858562306a36Sopenharmony_ci{
858662306a36Sopenharmony_ci	struct net_device *netdev = tp->netdev;
858762306a36Sopenharmony_ci
858862306a36Sopenharmony_ci	netif_device_detach(netdev);
858962306a36Sopenharmony_ci
859062306a36Sopenharmony_ci	if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
859162306a36Sopenharmony_ci		struct napi_struct *napi = &tp->napi;
859262306a36Sopenharmony_ci
859362306a36Sopenharmony_ci		clear_bit(WORK_ENABLE, &tp->flags);
859462306a36Sopenharmony_ci		usb_kill_urb(tp->intr_urb);
859562306a36Sopenharmony_ci		tasklet_disable(&tp->tx_tl);
859662306a36Sopenharmony_ci		napi_disable(napi);
859762306a36Sopenharmony_ci		cancel_delayed_work_sync(&tp->schedule);
859862306a36Sopenharmony_ci		tp->rtl_ops.down(tp);
859962306a36Sopenharmony_ci		napi_enable(napi);
860062306a36Sopenharmony_ci		tasklet_enable(&tp->tx_tl);
860162306a36Sopenharmony_ci	}
860262306a36Sopenharmony_ci
860362306a36Sopenharmony_ci	return 0;
860462306a36Sopenharmony_ci}
860562306a36Sopenharmony_ci
860662306a36Sopenharmony_cistatic int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
860762306a36Sopenharmony_ci{
860862306a36Sopenharmony_ci	struct r8152 *tp = usb_get_intfdata(intf);
860962306a36Sopenharmony_ci	int ret;
861062306a36Sopenharmony_ci
861162306a36Sopenharmony_ci	mutex_lock(&tp->control);
861262306a36Sopenharmony_ci
861362306a36Sopenharmony_ci	if (PMSG_IS_AUTO(message))
861462306a36Sopenharmony_ci		ret = rtl8152_runtime_suspend(tp);
861562306a36Sopenharmony_ci	else
861662306a36Sopenharmony_ci		ret = rtl8152_system_suspend(tp);
861762306a36Sopenharmony_ci
861862306a36Sopenharmony_ci	mutex_unlock(&tp->control);
861962306a36Sopenharmony_ci
862062306a36Sopenharmony_ci	return ret;
862162306a36Sopenharmony_ci}
862262306a36Sopenharmony_ci
862362306a36Sopenharmony_cistatic int rtl8152_resume(struct usb_interface *intf)
862462306a36Sopenharmony_ci{
862562306a36Sopenharmony_ci	struct r8152 *tp = usb_get_intfdata(intf);
862662306a36Sopenharmony_ci	int ret;
862762306a36Sopenharmony_ci
862862306a36Sopenharmony_ci	mutex_lock(&tp->control);
862962306a36Sopenharmony_ci
863062306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
863162306a36Sopenharmony_ci
863262306a36Sopenharmony_ci	if (test_bit(SELECTIVE_SUSPEND, &tp->flags))
863362306a36Sopenharmony_ci		ret = rtl8152_runtime_resume(tp);
863462306a36Sopenharmony_ci	else
863562306a36Sopenharmony_ci		ret = rtl8152_system_resume(tp);
863662306a36Sopenharmony_ci
863762306a36Sopenharmony_ci	mutex_unlock(&tp->control);
863862306a36Sopenharmony_ci
863962306a36Sopenharmony_ci	return ret;
864062306a36Sopenharmony_ci}
864162306a36Sopenharmony_ci
864262306a36Sopenharmony_cistatic int rtl8152_reset_resume(struct usb_interface *intf)
864362306a36Sopenharmony_ci{
864462306a36Sopenharmony_ci	struct r8152 *tp = usb_get_intfdata(intf);
864562306a36Sopenharmony_ci
864662306a36Sopenharmony_ci	clear_bit(SELECTIVE_SUSPEND, &tp->flags);
864762306a36Sopenharmony_ci	rtl_reset_ocp_base(tp);
864862306a36Sopenharmony_ci	tp->rtl_ops.init(tp);
864962306a36Sopenharmony_ci	queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
865062306a36Sopenharmony_ci	set_ethernet_addr(tp, true);
865162306a36Sopenharmony_ci	return rtl8152_resume(intf);
865262306a36Sopenharmony_ci}
865362306a36Sopenharmony_ci
865462306a36Sopenharmony_cistatic void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
865562306a36Sopenharmony_ci{
865662306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
865762306a36Sopenharmony_ci
865862306a36Sopenharmony_ci	if (usb_autopm_get_interface(tp->intf) < 0)
865962306a36Sopenharmony_ci		return;
866062306a36Sopenharmony_ci
866162306a36Sopenharmony_ci	if (!rtl_can_wakeup(tp)) {
866262306a36Sopenharmony_ci		wol->supported = 0;
866362306a36Sopenharmony_ci		wol->wolopts = 0;
866462306a36Sopenharmony_ci	} else {
866562306a36Sopenharmony_ci		mutex_lock(&tp->control);
866662306a36Sopenharmony_ci		wol->supported = WAKE_ANY;
866762306a36Sopenharmony_ci		wol->wolopts = __rtl_get_wol(tp);
866862306a36Sopenharmony_ci		mutex_unlock(&tp->control);
866962306a36Sopenharmony_ci	}
867062306a36Sopenharmony_ci
867162306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
867262306a36Sopenharmony_ci}
867362306a36Sopenharmony_ci
867462306a36Sopenharmony_cistatic int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
867562306a36Sopenharmony_ci{
867662306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
867762306a36Sopenharmony_ci	int ret;
867862306a36Sopenharmony_ci
867962306a36Sopenharmony_ci	if (!rtl_can_wakeup(tp))
868062306a36Sopenharmony_ci		return -EOPNOTSUPP;
868162306a36Sopenharmony_ci
868262306a36Sopenharmony_ci	if (wol->wolopts & ~WAKE_ANY)
868362306a36Sopenharmony_ci		return -EINVAL;
868462306a36Sopenharmony_ci
868562306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
868662306a36Sopenharmony_ci	if (ret < 0)
868762306a36Sopenharmony_ci		goto out_set_wol;
868862306a36Sopenharmony_ci
868962306a36Sopenharmony_ci	mutex_lock(&tp->control);
869062306a36Sopenharmony_ci
869162306a36Sopenharmony_ci	__rtl_set_wol(tp, wol->wolopts);
869262306a36Sopenharmony_ci	tp->saved_wolopts = wol->wolopts & WAKE_ANY;
869362306a36Sopenharmony_ci
869462306a36Sopenharmony_ci	mutex_unlock(&tp->control);
869562306a36Sopenharmony_ci
869662306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
869762306a36Sopenharmony_ci
869862306a36Sopenharmony_ciout_set_wol:
869962306a36Sopenharmony_ci	return ret;
870062306a36Sopenharmony_ci}
870162306a36Sopenharmony_ci
870262306a36Sopenharmony_cistatic u32 rtl8152_get_msglevel(struct net_device *dev)
870362306a36Sopenharmony_ci{
870462306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
870562306a36Sopenharmony_ci
870662306a36Sopenharmony_ci	return tp->msg_enable;
870762306a36Sopenharmony_ci}
870862306a36Sopenharmony_ci
870962306a36Sopenharmony_cistatic void rtl8152_set_msglevel(struct net_device *dev, u32 value)
871062306a36Sopenharmony_ci{
871162306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
871262306a36Sopenharmony_ci
871362306a36Sopenharmony_ci	tp->msg_enable = value;
871462306a36Sopenharmony_ci}
871562306a36Sopenharmony_ci
871662306a36Sopenharmony_cistatic void rtl8152_get_drvinfo(struct net_device *netdev,
871762306a36Sopenharmony_ci				struct ethtool_drvinfo *info)
871862306a36Sopenharmony_ci{
871962306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
872062306a36Sopenharmony_ci
872162306a36Sopenharmony_ci	strscpy(info->driver, MODULENAME, sizeof(info->driver));
872262306a36Sopenharmony_ci	strscpy(info->version, DRIVER_VERSION, sizeof(info->version));
872362306a36Sopenharmony_ci	usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info));
872462306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(tp->rtl_fw.fw))
872562306a36Sopenharmony_ci		strscpy(info->fw_version, tp->rtl_fw.version,
872662306a36Sopenharmony_ci			sizeof(info->fw_version));
872762306a36Sopenharmony_ci}
872862306a36Sopenharmony_ci
872962306a36Sopenharmony_cistatic
873062306a36Sopenharmony_ciint rtl8152_get_link_ksettings(struct net_device *netdev,
873162306a36Sopenharmony_ci			       struct ethtool_link_ksettings *cmd)
873262306a36Sopenharmony_ci{
873362306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
873462306a36Sopenharmony_ci	int ret;
873562306a36Sopenharmony_ci
873662306a36Sopenharmony_ci	if (!tp->mii.mdio_read)
873762306a36Sopenharmony_ci		return -EOPNOTSUPP;
873862306a36Sopenharmony_ci
873962306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
874062306a36Sopenharmony_ci	if (ret < 0)
874162306a36Sopenharmony_ci		goto out;
874262306a36Sopenharmony_ci
874362306a36Sopenharmony_ci	mutex_lock(&tp->control);
874462306a36Sopenharmony_ci
874562306a36Sopenharmony_ci	mii_ethtool_get_link_ksettings(&tp->mii, cmd);
874662306a36Sopenharmony_ci
874762306a36Sopenharmony_ci	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
874862306a36Sopenharmony_ci			 cmd->link_modes.supported, tp->support_2500full);
874962306a36Sopenharmony_ci
875062306a36Sopenharmony_ci	if (tp->support_2500full) {
875162306a36Sopenharmony_ci		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
875262306a36Sopenharmony_ci				 cmd->link_modes.advertising,
875362306a36Sopenharmony_ci				 ocp_reg_read(tp, OCP_10GBT_CTRL) & MDIO_AN_10GBT_CTRL_ADV2_5G);
875462306a36Sopenharmony_ci
875562306a36Sopenharmony_ci		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
875662306a36Sopenharmony_ci				 cmd->link_modes.lp_advertising,
875762306a36Sopenharmony_ci				 ocp_reg_read(tp, OCP_10GBT_STAT) & MDIO_AN_10GBT_STAT_LP2_5G);
875862306a36Sopenharmony_ci
875962306a36Sopenharmony_ci		if (is_speed_2500(rtl8152_get_speed(tp)))
876062306a36Sopenharmony_ci			cmd->base.speed = SPEED_2500;
876162306a36Sopenharmony_ci	}
876262306a36Sopenharmony_ci
876362306a36Sopenharmony_ci	mutex_unlock(&tp->control);
876462306a36Sopenharmony_ci
876562306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
876662306a36Sopenharmony_ci
876762306a36Sopenharmony_ciout:
876862306a36Sopenharmony_ci	return ret;
876962306a36Sopenharmony_ci}
877062306a36Sopenharmony_ci
877162306a36Sopenharmony_cistatic int rtl8152_set_link_ksettings(struct net_device *dev,
877262306a36Sopenharmony_ci				      const struct ethtool_link_ksettings *cmd)
877362306a36Sopenharmony_ci{
877462306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
877562306a36Sopenharmony_ci	u32 advertising = 0;
877662306a36Sopenharmony_ci	int ret;
877762306a36Sopenharmony_ci
877862306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
877962306a36Sopenharmony_ci	if (ret < 0)
878062306a36Sopenharmony_ci		goto out;
878162306a36Sopenharmony_ci
878262306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
878362306a36Sopenharmony_ci		     cmd->link_modes.advertising))
878462306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_10_HALF;
878562306a36Sopenharmony_ci
878662306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
878762306a36Sopenharmony_ci		     cmd->link_modes.advertising))
878862306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_10_FULL;
878962306a36Sopenharmony_ci
879062306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
879162306a36Sopenharmony_ci		     cmd->link_modes.advertising))
879262306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_100_HALF;
879362306a36Sopenharmony_ci
879462306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
879562306a36Sopenharmony_ci		     cmd->link_modes.advertising))
879662306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_100_FULL;
879762306a36Sopenharmony_ci
879862306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
879962306a36Sopenharmony_ci		     cmd->link_modes.advertising))
880062306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_1000_HALF;
880162306a36Sopenharmony_ci
880262306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
880362306a36Sopenharmony_ci		     cmd->link_modes.advertising))
880462306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_1000_FULL;
880562306a36Sopenharmony_ci
880662306a36Sopenharmony_ci	if (test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
880762306a36Sopenharmony_ci		     cmd->link_modes.advertising))
880862306a36Sopenharmony_ci		advertising |= RTL_ADVERTISED_2500_FULL;
880962306a36Sopenharmony_ci
881062306a36Sopenharmony_ci	mutex_lock(&tp->control);
881162306a36Sopenharmony_ci
881262306a36Sopenharmony_ci	ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed,
881362306a36Sopenharmony_ci				cmd->base.duplex, advertising);
881462306a36Sopenharmony_ci	if (!ret) {
881562306a36Sopenharmony_ci		tp->autoneg = cmd->base.autoneg;
881662306a36Sopenharmony_ci		tp->speed = cmd->base.speed;
881762306a36Sopenharmony_ci		tp->duplex = cmd->base.duplex;
881862306a36Sopenharmony_ci		tp->advertising = advertising;
881962306a36Sopenharmony_ci	}
882062306a36Sopenharmony_ci
882162306a36Sopenharmony_ci	mutex_unlock(&tp->control);
882262306a36Sopenharmony_ci
882362306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
882462306a36Sopenharmony_ci
882562306a36Sopenharmony_ciout:
882662306a36Sopenharmony_ci	return ret;
882762306a36Sopenharmony_ci}
882862306a36Sopenharmony_ci
882962306a36Sopenharmony_cistatic const char rtl8152_gstrings[][ETH_GSTRING_LEN] = {
883062306a36Sopenharmony_ci	"tx_packets",
883162306a36Sopenharmony_ci	"rx_packets",
883262306a36Sopenharmony_ci	"tx_errors",
883362306a36Sopenharmony_ci	"rx_errors",
883462306a36Sopenharmony_ci	"rx_missed",
883562306a36Sopenharmony_ci	"align_errors",
883662306a36Sopenharmony_ci	"tx_single_collisions",
883762306a36Sopenharmony_ci	"tx_multi_collisions",
883862306a36Sopenharmony_ci	"rx_unicast",
883962306a36Sopenharmony_ci	"rx_broadcast",
884062306a36Sopenharmony_ci	"rx_multicast",
884162306a36Sopenharmony_ci	"tx_aborted",
884262306a36Sopenharmony_ci	"tx_underrun",
884362306a36Sopenharmony_ci};
884462306a36Sopenharmony_ci
884562306a36Sopenharmony_cistatic int rtl8152_get_sset_count(struct net_device *dev, int sset)
884662306a36Sopenharmony_ci{
884762306a36Sopenharmony_ci	switch (sset) {
884862306a36Sopenharmony_ci	case ETH_SS_STATS:
884962306a36Sopenharmony_ci		return ARRAY_SIZE(rtl8152_gstrings);
885062306a36Sopenharmony_ci	default:
885162306a36Sopenharmony_ci		return -EOPNOTSUPP;
885262306a36Sopenharmony_ci	}
885362306a36Sopenharmony_ci}
885462306a36Sopenharmony_ci
885562306a36Sopenharmony_cistatic void rtl8152_get_ethtool_stats(struct net_device *dev,
885662306a36Sopenharmony_ci				      struct ethtool_stats *stats, u64 *data)
885762306a36Sopenharmony_ci{
885862306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
885962306a36Sopenharmony_ci	struct tally_counter tally;
886062306a36Sopenharmony_ci
886162306a36Sopenharmony_ci	if (usb_autopm_get_interface(tp->intf) < 0)
886262306a36Sopenharmony_ci		return;
886362306a36Sopenharmony_ci
886462306a36Sopenharmony_ci	generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA);
886562306a36Sopenharmony_ci
886662306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
886762306a36Sopenharmony_ci
886862306a36Sopenharmony_ci	data[0] = le64_to_cpu(tally.tx_packets);
886962306a36Sopenharmony_ci	data[1] = le64_to_cpu(tally.rx_packets);
887062306a36Sopenharmony_ci	data[2] = le64_to_cpu(tally.tx_errors);
887162306a36Sopenharmony_ci	data[3] = le32_to_cpu(tally.rx_errors);
887262306a36Sopenharmony_ci	data[4] = le16_to_cpu(tally.rx_missed);
887362306a36Sopenharmony_ci	data[5] = le16_to_cpu(tally.align_errors);
887462306a36Sopenharmony_ci	data[6] = le32_to_cpu(tally.tx_one_collision);
887562306a36Sopenharmony_ci	data[7] = le32_to_cpu(tally.tx_multi_collision);
887662306a36Sopenharmony_ci	data[8] = le64_to_cpu(tally.rx_unicast);
887762306a36Sopenharmony_ci	data[9] = le64_to_cpu(tally.rx_broadcast);
887862306a36Sopenharmony_ci	data[10] = le32_to_cpu(tally.rx_multicast);
887962306a36Sopenharmony_ci	data[11] = le16_to_cpu(tally.tx_aborted);
888062306a36Sopenharmony_ci	data[12] = le16_to_cpu(tally.tx_underrun);
888162306a36Sopenharmony_ci}
888262306a36Sopenharmony_ci
888362306a36Sopenharmony_cistatic void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
888462306a36Sopenharmony_ci{
888562306a36Sopenharmony_ci	switch (stringset) {
888662306a36Sopenharmony_ci	case ETH_SS_STATS:
888762306a36Sopenharmony_ci		memcpy(data, rtl8152_gstrings, sizeof(rtl8152_gstrings));
888862306a36Sopenharmony_ci		break;
888962306a36Sopenharmony_ci	}
889062306a36Sopenharmony_ci}
889162306a36Sopenharmony_ci
889262306a36Sopenharmony_cistatic int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee)
889362306a36Sopenharmony_ci{
889462306a36Sopenharmony_ci	u32 lp, adv, supported = 0;
889562306a36Sopenharmony_ci	u16 val;
889662306a36Sopenharmony_ci
889762306a36Sopenharmony_ci	val = r8152_mmd_read(tp, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
889862306a36Sopenharmony_ci	supported = mmd_eee_cap_to_ethtool_sup_t(val);
889962306a36Sopenharmony_ci
890062306a36Sopenharmony_ci	val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
890162306a36Sopenharmony_ci	adv = mmd_eee_adv_to_ethtool_adv_t(val);
890262306a36Sopenharmony_ci
890362306a36Sopenharmony_ci	val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE);
890462306a36Sopenharmony_ci	lp = mmd_eee_adv_to_ethtool_adv_t(val);
890562306a36Sopenharmony_ci
890662306a36Sopenharmony_ci	eee->eee_enabled = tp->eee_en;
890762306a36Sopenharmony_ci	eee->eee_active = !!(supported & adv & lp);
890862306a36Sopenharmony_ci	eee->supported = supported;
890962306a36Sopenharmony_ci	eee->advertised = tp->eee_adv;
891062306a36Sopenharmony_ci	eee->lp_advertised = lp;
891162306a36Sopenharmony_ci
891262306a36Sopenharmony_ci	return 0;
891362306a36Sopenharmony_ci}
891462306a36Sopenharmony_ci
891562306a36Sopenharmony_cistatic int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee)
891662306a36Sopenharmony_ci{
891762306a36Sopenharmony_ci	u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised);
891862306a36Sopenharmony_ci
891962306a36Sopenharmony_ci	tp->eee_en = eee->eee_enabled;
892062306a36Sopenharmony_ci	tp->eee_adv = val;
892162306a36Sopenharmony_ci
892262306a36Sopenharmony_ci	rtl_eee_enable(tp, tp->eee_en);
892362306a36Sopenharmony_ci
892462306a36Sopenharmony_ci	return 0;
892562306a36Sopenharmony_ci}
892662306a36Sopenharmony_ci
892762306a36Sopenharmony_cistatic int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee)
892862306a36Sopenharmony_ci{
892962306a36Sopenharmony_ci	u32 lp, adv, supported = 0;
893062306a36Sopenharmony_ci	u16 val;
893162306a36Sopenharmony_ci
893262306a36Sopenharmony_ci	val = ocp_reg_read(tp, OCP_EEE_ABLE);
893362306a36Sopenharmony_ci	supported = mmd_eee_cap_to_ethtool_sup_t(val);
893462306a36Sopenharmony_ci
893562306a36Sopenharmony_ci	val = ocp_reg_read(tp, OCP_EEE_ADV);
893662306a36Sopenharmony_ci	adv = mmd_eee_adv_to_ethtool_adv_t(val);
893762306a36Sopenharmony_ci
893862306a36Sopenharmony_ci	val = ocp_reg_read(tp, OCP_EEE_LPABLE);
893962306a36Sopenharmony_ci	lp = mmd_eee_adv_to_ethtool_adv_t(val);
894062306a36Sopenharmony_ci
894162306a36Sopenharmony_ci	eee->eee_enabled = tp->eee_en;
894262306a36Sopenharmony_ci	eee->eee_active = !!(supported & adv & lp);
894362306a36Sopenharmony_ci	eee->supported = supported;
894462306a36Sopenharmony_ci	eee->advertised = tp->eee_adv;
894562306a36Sopenharmony_ci	eee->lp_advertised = lp;
894662306a36Sopenharmony_ci
894762306a36Sopenharmony_ci	return 0;
894862306a36Sopenharmony_ci}
894962306a36Sopenharmony_ci
895062306a36Sopenharmony_cistatic int
895162306a36Sopenharmony_cirtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata)
895262306a36Sopenharmony_ci{
895362306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(net);
895462306a36Sopenharmony_ci	int ret;
895562306a36Sopenharmony_ci
895662306a36Sopenharmony_ci	if (!tp->rtl_ops.eee_get) {
895762306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
895862306a36Sopenharmony_ci		goto out;
895962306a36Sopenharmony_ci	}
896062306a36Sopenharmony_ci
896162306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
896262306a36Sopenharmony_ci	if (ret < 0)
896362306a36Sopenharmony_ci		goto out;
896462306a36Sopenharmony_ci
896562306a36Sopenharmony_ci	mutex_lock(&tp->control);
896662306a36Sopenharmony_ci
896762306a36Sopenharmony_ci	ret = tp->rtl_ops.eee_get(tp, edata);
896862306a36Sopenharmony_ci
896962306a36Sopenharmony_ci	mutex_unlock(&tp->control);
897062306a36Sopenharmony_ci
897162306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
897262306a36Sopenharmony_ci
897362306a36Sopenharmony_ciout:
897462306a36Sopenharmony_ci	return ret;
897562306a36Sopenharmony_ci}
897662306a36Sopenharmony_ci
897762306a36Sopenharmony_cistatic int
897862306a36Sopenharmony_cirtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata)
897962306a36Sopenharmony_ci{
898062306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(net);
898162306a36Sopenharmony_ci	int ret;
898262306a36Sopenharmony_ci
898362306a36Sopenharmony_ci	if (!tp->rtl_ops.eee_set) {
898462306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
898562306a36Sopenharmony_ci		goto out;
898662306a36Sopenharmony_ci	}
898762306a36Sopenharmony_ci
898862306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
898962306a36Sopenharmony_ci	if (ret < 0)
899062306a36Sopenharmony_ci		goto out;
899162306a36Sopenharmony_ci
899262306a36Sopenharmony_ci	mutex_lock(&tp->control);
899362306a36Sopenharmony_ci
899462306a36Sopenharmony_ci	ret = tp->rtl_ops.eee_set(tp, edata);
899562306a36Sopenharmony_ci	if (!ret)
899662306a36Sopenharmony_ci		ret = mii_nway_restart(&tp->mii);
899762306a36Sopenharmony_ci
899862306a36Sopenharmony_ci	mutex_unlock(&tp->control);
899962306a36Sopenharmony_ci
900062306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
900162306a36Sopenharmony_ci
900262306a36Sopenharmony_ciout:
900362306a36Sopenharmony_ci	return ret;
900462306a36Sopenharmony_ci}
900562306a36Sopenharmony_ci
900662306a36Sopenharmony_cistatic int rtl8152_nway_reset(struct net_device *dev)
900762306a36Sopenharmony_ci{
900862306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
900962306a36Sopenharmony_ci	int ret;
901062306a36Sopenharmony_ci
901162306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
901262306a36Sopenharmony_ci	if (ret < 0)
901362306a36Sopenharmony_ci		goto out;
901462306a36Sopenharmony_ci
901562306a36Sopenharmony_ci	mutex_lock(&tp->control);
901662306a36Sopenharmony_ci
901762306a36Sopenharmony_ci	ret = mii_nway_restart(&tp->mii);
901862306a36Sopenharmony_ci
901962306a36Sopenharmony_ci	mutex_unlock(&tp->control);
902062306a36Sopenharmony_ci
902162306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
902262306a36Sopenharmony_ci
902362306a36Sopenharmony_ciout:
902462306a36Sopenharmony_ci	return ret;
902562306a36Sopenharmony_ci}
902662306a36Sopenharmony_ci
902762306a36Sopenharmony_cistatic int rtl8152_get_coalesce(struct net_device *netdev,
902862306a36Sopenharmony_ci				struct ethtool_coalesce *coalesce,
902962306a36Sopenharmony_ci				struct kernel_ethtool_coalesce *kernel_coal,
903062306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
903162306a36Sopenharmony_ci{
903262306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
903362306a36Sopenharmony_ci
903462306a36Sopenharmony_ci	switch (tp->version) {
903562306a36Sopenharmony_ci	case RTL_VER_01:
903662306a36Sopenharmony_ci	case RTL_VER_02:
903762306a36Sopenharmony_ci	case RTL_VER_07:
903862306a36Sopenharmony_ci		return -EOPNOTSUPP;
903962306a36Sopenharmony_ci	default:
904062306a36Sopenharmony_ci		break;
904162306a36Sopenharmony_ci	}
904262306a36Sopenharmony_ci
904362306a36Sopenharmony_ci	coalesce->rx_coalesce_usecs = tp->coalesce;
904462306a36Sopenharmony_ci
904562306a36Sopenharmony_ci	return 0;
904662306a36Sopenharmony_ci}
904762306a36Sopenharmony_ci
904862306a36Sopenharmony_cistatic int rtl8152_set_coalesce(struct net_device *netdev,
904962306a36Sopenharmony_ci				struct ethtool_coalesce *coalesce,
905062306a36Sopenharmony_ci				struct kernel_ethtool_coalesce *kernel_coal,
905162306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
905262306a36Sopenharmony_ci{
905362306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
905462306a36Sopenharmony_ci	int ret;
905562306a36Sopenharmony_ci
905662306a36Sopenharmony_ci	switch (tp->version) {
905762306a36Sopenharmony_ci	case RTL_VER_01:
905862306a36Sopenharmony_ci	case RTL_VER_02:
905962306a36Sopenharmony_ci	case RTL_VER_07:
906062306a36Sopenharmony_ci		return -EOPNOTSUPP;
906162306a36Sopenharmony_ci	default:
906262306a36Sopenharmony_ci		break;
906362306a36Sopenharmony_ci	}
906462306a36Sopenharmony_ci
906562306a36Sopenharmony_ci	if (coalesce->rx_coalesce_usecs > COALESCE_SLOW)
906662306a36Sopenharmony_ci		return -EINVAL;
906762306a36Sopenharmony_ci
906862306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
906962306a36Sopenharmony_ci	if (ret < 0)
907062306a36Sopenharmony_ci		return ret;
907162306a36Sopenharmony_ci
907262306a36Sopenharmony_ci	mutex_lock(&tp->control);
907362306a36Sopenharmony_ci
907462306a36Sopenharmony_ci	if (tp->coalesce != coalesce->rx_coalesce_usecs) {
907562306a36Sopenharmony_ci		tp->coalesce = coalesce->rx_coalesce_usecs;
907662306a36Sopenharmony_ci
907762306a36Sopenharmony_ci		if (netif_running(netdev) && netif_carrier_ok(netdev)) {
907862306a36Sopenharmony_ci			netif_stop_queue(netdev);
907962306a36Sopenharmony_ci			napi_disable(&tp->napi);
908062306a36Sopenharmony_ci			tp->rtl_ops.disable(tp);
908162306a36Sopenharmony_ci			tp->rtl_ops.enable(tp);
908262306a36Sopenharmony_ci			rtl_start_rx(tp);
908362306a36Sopenharmony_ci			clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
908462306a36Sopenharmony_ci			_rtl8152_set_rx_mode(netdev);
908562306a36Sopenharmony_ci			napi_enable(&tp->napi);
908662306a36Sopenharmony_ci			netif_wake_queue(netdev);
908762306a36Sopenharmony_ci		}
908862306a36Sopenharmony_ci	}
908962306a36Sopenharmony_ci
909062306a36Sopenharmony_ci	mutex_unlock(&tp->control);
909162306a36Sopenharmony_ci
909262306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
909362306a36Sopenharmony_ci
909462306a36Sopenharmony_ci	return ret;
909562306a36Sopenharmony_ci}
909662306a36Sopenharmony_ci
909762306a36Sopenharmony_cistatic int rtl8152_get_tunable(struct net_device *netdev,
909862306a36Sopenharmony_ci			       const struct ethtool_tunable *tunable, void *d)
909962306a36Sopenharmony_ci{
910062306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
910162306a36Sopenharmony_ci
910262306a36Sopenharmony_ci	switch (tunable->id) {
910362306a36Sopenharmony_ci	case ETHTOOL_RX_COPYBREAK:
910462306a36Sopenharmony_ci		*(u32 *)d = tp->rx_copybreak;
910562306a36Sopenharmony_ci		break;
910662306a36Sopenharmony_ci	default:
910762306a36Sopenharmony_ci		return -EOPNOTSUPP;
910862306a36Sopenharmony_ci	}
910962306a36Sopenharmony_ci
911062306a36Sopenharmony_ci	return 0;
911162306a36Sopenharmony_ci}
911262306a36Sopenharmony_ci
911362306a36Sopenharmony_cistatic int rtl8152_set_tunable(struct net_device *netdev,
911462306a36Sopenharmony_ci			       const struct ethtool_tunable *tunable,
911562306a36Sopenharmony_ci			       const void *d)
911662306a36Sopenharmony_ci{
911762306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
911862306a36Sopenharmony_ci	u32 val;
911962306a36Sopenharmony_ci
912062306a36Sopenharmony_ci	switch (tunable->id) {
912162306a36Sopenharmony_ci	case ETHTOOL_RX_COPYBREAK:
912262306a36Sopenharmony_ci		val = *(u32 *)d;
912362306a36Sopenharmony_ci		if (val < ETH_ZLEN) {
912462306a36Sopenharmony_ci			netif_err(tp, rx_err, netdev,
912562306a36Sopenharmony_ci				  "Invalid rx copy break value\n");
912662306a36Sopenharmony_ci			return -EINVAL;
912762306a36Sopenharmony_ci		}
912862306a36Sopenharmony_ci
912962306a36Sopenharmony_ci		if (tp->rx_copybreak != val) {
913062306a36Sopenharmony_ci			if (netdev->flags & IFF_UP) {
913162306a36Sopenharmony_ci				mutex_lock(&tp->control);
913262306a36Sopenharmony_ci				napi_disable(&tp->napi);
913362306a36Sopenharmony_ci				tp->rx_copybreak = val;
913462306a36Sopenharmony_ci				napi_enable(&tp->napi);
913562306a36Sopenharmony_ci				mutex_unlock(&tp->control);
913662306a36Sopenharmony_ci			} else {
913762306a36Sopenharmony_ci				tp->rx_copybreak = val;
913862306a36Sopenharmony_ci			}
913962306a36Sopenharmony_ci		}
914062306a36Sopenharmony_ci		break;
914162306a36Sopenharmony_ci	default:
914262306a36Sopenharmony_ci		return -EOPNOTSUPP;
914362306a36Sopenharmony_ci	}
914462306a36Sopenharmony_ci
914562306a36Sopenharmony_ci	return 0;
914662306a36Sopenharmony_ci}
914762306a36Sopenharmony_ci
914862306a36Sopenharmony_cistatic void rtl8152_get_ringparam(struct net_device *netdev,
914962306a36Sopenharmony_ci				  struct ethtool_ringparam *ring,
915062306a36Sopenharmony_ci				  struct kernel_ethtool_ringparam *kernel_ring,
915162306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
915262306a36Sopenharmony_ci{
915362306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
915462306a36Sopenharmony_ci
915562306a36Sopenharmony_ci	ring->rx_max_pending = RTL8152_RX_MAX_PENDING;
915662306a36Sopenharmony_ci	ring->rx_pending = tp->rx_pending;
915762306a36Sopenharmony_ci}
915862306a36Sopenharmony_ci
915962306a36Sopenharmony_cistatic int rtl8152_set_ringparam(struct net_device *netdev,
916062306a36Sopenharmony_ci				 struct ethtool_ringparam *ring,
916162306a36Sopenharmony_ci				 struct kernel_ethtool_ringparam *kernel_ring,
916262306a36Sopenharmony_ci				 struct netlink_ext_ack *extack)
916362306a36Sopenharmony_ci{
916462306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
916562306a36Sopenharmony_ci
916662306a36Sopenharmony_ci	if (ring->rx_pending < (RTL8152_MAX_RX * 2))
916762306a36Sopenharmony_ci		return -EINVAL;
916862306a36Sopenharmony_ci
916962306a36Sopenharmony_ci	if (tp->rx_pending != ring->rx_pending) {
917062306a36Sopenharmony_ci		if (netdev->flags & IFF_UP) {
917162306a36Sopenharmony_ci			mutex_lock(&tp->control);
917262306a36Sopenharmony_ci			napi_disable(&tp->napi);
917362306a36Sopenharmony_ci			tp->rx_pending = ring->rx_pending;
917462306a36Sopenharmony_ci			napi_enable(&tp->napi);
917562306a36Sopenharmony_ci			mutex_unlock(&tp->control);
917662306a36Sopenharmony_ci		} else {
917762306a36Sopenharmony_ci			tp->rx_pending = ring->rx_pending;
917862306a36Sopenharmony_ci		}
917962306a36Sopenharmony_ci	}
918062306a36Sopenharmony_ci
918162306a36Sopenharmony_ci	return 0;
918262306a36Sopenharmony_ci}
918362306a36Sopenharmony_ci
918462306a36Sopenharmony_cistatic void rtl8152_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
918562306a36Sopenharmony_ci{
918662306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
918762306a36Sopenharmony_ci	u16 bmcr, lcladv, rmtadv;
918862306a36Sopenharmony_ci	u8 cap;
918962306a36Sopenharmony_ci
919062306a36Sopenharmony_ci	if (usb_autopm_get_interface(tp->intf) < 0)
919162306a36Sopenharmony_ci		return;
919262306a36Sopenharmony_ci
919362306a36Sopenharmony_ci	mutex_lock(&tp->control);
919462306a36Sopenharmony_ci
919562306a36Sopenharmony_ci	bmcr = r8152_mdio_read(tp, MII_BMCR);
919662306a36Sopenharmony_ci	lcladv = r8152_mdio_read(tp, MII_ADVERTISE);
919762306a36Sopenharmony_ci	rmtadv = r8152_mdio_read(tp, MII_LPA);
919862306a36Sopenharmony_ci
919962306a36Sopenharmony_ci	mutex_unlock(&tp->control);
920062306a36Sopenharmony_ci
920162306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
920262306a36Sopenharmony_ci
920362306a36Sopenharmony_ci	if (!(bmcr & BMCR_ANENABLE)) {
920462306a36Sopenharmony_ci		pause->autoneg = 0;
920562306a36Sopenharmony_ci		pause->rx_pause = 0;
920662306a36Sopenharmony_ci		pause->tx_pause = 0;
920762306a36Sopenharmony_ci		return;
920862306a36Sopenharmony_ci	}
920962306a36Sopenharmony_ci
921062306a36Sopenharmony_ci	pause->autoneg = 1;
921162306a36Sopenharmony_ci
921262306a36Sopenharmony_ci	cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
921362306a36Sopenharmony_ci
921462306a36Sopenharmony_ci	if (cap & FLOW_CTRL_RX)
921562306a36Sopenharmony_ci		pause->rx_pause = 1;
921662306a36Sopenharmony_ci
921762306a36Sopenharmony_ci	if (cap & FLOW_CTRL_TX)
921862306a36Sopenharmony_ci		pause->tx_pause = 1;
921962306a36Sopenharmony_ci}
922062306a36Sopenharmony_ci
922162306a36Sopenharmony_cistatic int rtl8152_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
922262306a36Sopenharmony_ci{
922362306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
922462306a36Sopenharmony_ci	u16 old, new1;
922562306a36Sopenharmony_ci	u8 cap = 0;
922662306a36Sopenharmony_ci	int ret;
922762306a36Sopenharmony_ci
922862306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
922962306a36Sopenharmony_ci	if (ret < 0)
923062306a36Sopenharmony_ci		return ret;
923162306a36Sopenharmony_ci
923262306a36Sopenharmony_ci	mutex_lock(&tp->control);
923362306a36Sopenharmony_ci
923462306a36Sopenharmony_ci	if (pause->autoneg && !(r8152_mdio_read(tp, MII_BMCR) & BMCR_ANENABLE)) {
923562306a36Sopenharmony_ci		ret = -EINVAL;
923662306a36Sopenharmony_ci		goto out;
923762306a36Sopenharmony_ci	}
923862306a36Sopenharmony_ci
923962306a36Sopenharmony_ci	if (pause->rx_pause)
924062306a36Sopenharmony_ci		cap |= FLOW_CTRL_RX;
924162306a36Sopenharmony_ci
924262306a36Sopenharmony_ci	if (pause->tx_pause)
924362306a36Sopenharmony_ci		cap |= FLOW_CTRL_TX;
924462306a36Sopenharmony_ci
924562306a36Sopenharmony_ci	old = r8152_mdio_read(tp, MII_ADVERTISE);
924662306a36Sopenharmony_ci	new1 = (old & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) | mii_advertise_flowctrl(cap);
924762306a36Sopenharmony_ci	if (old != new1)
924862306a36Sopenharmony_ci		r8152_mdio_write(tp, MII_ADVERTISE, new1);
924962306a36Sopenharmony_ci
925062306a36Sopenharmony_ciout:
925162306a36Sopenharmony_ci	mutex_unlock(&tp->control);
925262306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
925362306a36Sopenharmony_ci
925462306a36Sopenharmony_ci	return ret;
925562306a36Sopenharmony_ci}
925662306a36Sopenharmony_ci
925762306a36Sopenharmony_cistatic const struct ethtool_ops ops = {
925862306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
925962306a36Sopenharmony_ci	.get_drvinfo = rtl8152_get_drvinfo,
926062306a36Sopenharmony_ci	.get_link = ethtool_op_get_link,
926162306a36Sopenharmony_ci	.nway_reset = rtl8152_nway_reset,
926262306a36Sopenharmony_ci	.get_msglevel = rtl8152_get_msglevel,
926362306a36Sopenharmony_ci	.set_msglevel = rtl8152_set_msglevel,
926462306a36Sopenharmony_ci	.get_wol = rtl8152_get_wol,
926562306a36Sopenharmony_ci	.set_wol = rtl8152_set_wol,
926662306a36Sopenharmony_ci	.get_strings = rtl8152_get_strings,
926762306a36Sopenharmony_ci	.get_sset_count = rtl8152_get_sset_count,
926862306a36Sopenharmony_ci	.get_ethtool_stats = rtl8152_get_ethtool_stats,
926962306a36Sopenharmony_ci	.get_coalesce = rtl8152_get_coalesce,
927062306a36Sopenharmony_ci	.set_coalesce = rtl8152_set_coalesce,
927162306a36Sopenharmony_ci	.get_eee = rtl_ethtool_get_eee,
927262306a36Sopenharmony_ci	.set_eee = rtl_ethtool_set_eee,
927362306a36Sopenharmony_ci	.get_link_ksettings = rtl8152_get_link_ksettings,
927462306a36Sopenharmony_ci	.set_link_ksettings = rtl8152_set_link_ksettings,
927562306a36Sopenharmony_ci	.get_tunable = rtl8152_get_tunable,
927662306a36Sopenharmony_ci	.set_tunable = rtl8152_set_tunable,
927762306a36Sopenharmony_ci	.get_ringparam = rtl8152_get_ringparam,
927862306a36Sopenharmony_ci	.set_ringparam = rtl8152_set_ringparam,
927962306a36Sopenharmony_ci	.get_pauseparam = rtl8152_get_pauseparam,
928062306a36Sopenharmony_ci	.set_pauseparam = rtl8152_set_pauseparam,
928162306a36Sopenharmony_ci};
928262306a36Sopenharmony_ci
928362306a36Sopenharmony_cistatic int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
928462306a36Sopenharmony_ci{
928562306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(netdev);
928662306a36Sopenharmony_ci	struct mii_ioctl_data *data = if_mii(rq);
928762306a36Sopenharmony_ci	int res;
928862306a36Sopenharmony_ci
928962306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
929062306a36Sopenharmony_ci		return -ENODEV;
929162306a36Sopenharmony_ci
929262306a36Sopenharmony_ci	res = usb_autopm_get_interface(tp->intf);
929362306a36Sopenharmony_ci	if (res < 0)
929462306a36Sopenharmony_ci		goto out;
929562306a36Sopenharmony_ci
929662306a36Sopenharmony_ci	switch (cmd) {
929762306a36Sopenharmony_ci	case SIOCGMIIPHY:
929862306a36Sopenharmony_ci		data->phy_id = R8152_PHY_ID; /* Internal PHY */
929962306a36Sopenharmony_ci		break;
930062306a36Sopenharmony_ci
930162306a36Sopenharmony_ci	case SIOCGMIIREG:
930262306a36Sopenharmony_ci		mutex_lock(&tp->control);
930362306a36Sopenharmony_ci		data->val_out = r8152_mdio_read(tp, data->reg_num);
930462306a36Sopenharmony_ci		mutex_unlock(&tp->control);
930562306a36Sopenharmony_ci		break;
930662306a36Sopenharmony_ci
930762306a36Sopenharmony_ci	case SIOCSMIIREG:
930862306a36Sopenharmony_ci		if (!capable(CAP_NET_ADMIN)) {
930962306a36Sopenharmony_ci			res = -EPERM;
931062306a36Sopenharmony_ci			break;
931162306a36Sopenharmony_ci		}
931262306a36Sopenharmony_ci		mutex_lock(&tp->control);
931362306a36Sopenharmony_ci		r8152_mdio_write(tp, data->reg_num, data->val_in);
931462306a36Sopenharmony_ci		mutex_unlock(&tp->control);
931562306a36Sopenharmony_ci		break;
931662306a36Sopenharmony_ci
931762306a36Sopenharmony_ci	default:
931862306a36Sopenharmony_ci		res = -EOPNOTSUPP;
931962306a36Sopenharmony_ci	}
932062306a36Sopenharmony_ci
932162306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
932262306a36Sopenharmony_ci
932362306a36Sopenharmony_ciout:
932462306a36Sopenharmony_ci	return res;
932562306a36Sopenharmony_ci}
932662306a36Sopenharmony_ci
932762306a36Sopenharmony_cistatic int rtl8152_change_mtu(struct net_device *dev, int new_mtu)
932862306a36Sopenharmony_ci{
932962306a36Sopenharmony_ci	struct r8152 *tp = netdev_priv(dev);
933062306a36Sopenharmony_ci	int ret;
933162306a36Sopenharmony_ci
933262306a36Sopenharmony_ci	switch (tp->version) {
933362306a36Sopenharmony_ci	case RTL_VER_01:
933462306a36Sopenharmony_ci	case RTL_VER_02:
933562306a36Sopenharmony_ci	case RTL_VER_07:
933662306a36Sopenharmony_ci		dev->mtu = new_mtu;
933762306a36Sopenharmony_ci		return 0;
933862306a36Sopenharmony_ci	default:
933962306a36Sopenharmony_ci		break;
934062306a36Sopenharmony_ci	}
934162306a36Sopenharmony_ci
934262306a36Sopenharmony_ci	ret = usb_autopm_get_interface(tp->intf);
934362306a36Sopenharmony_ci	if (ret < 0)
934462306a36Sopenharmony_ci		return ret;
934562306a36Sopenharmony_ci
934662306a36Sopenharmony_ci	mutex_lock(&tp->control);
934762306a36Sopenharmony_ci
934862306a36Sopenharmony_ci	dev->mtu = new_mtu;
934962306a36Sopenharmony_ci
935062306a36Sopenharmony_ci	if (netif_running(dev)) {
935162306a36Sopenharmony_ci		if (tp->rtl_ops.change_mtu)
935262306a36Sopenharmony_ci			tp->rtl_ops.change_mtu(tp);
935362306a36Sopenharmony_ci
935462306a36Sopenharmony_ci		if (netif_carrier_ok(dev)) {
935562306a36Sopenharmony_ci			netif_stop_queue(dev);
935662306a36Sopenharmony_ci			napi_disable(&tp->napi);
935762306a36Sopenharmony_ci			tasklet_disable(&tp->tx_tl);
935862306a36Sopenharmony_ci			tp->rtl_ops.disable(tp);
935962306a36Sopenharmony_ci			tp->rtl_ops.enable(tp);
936062306a36Sopenharmony_ci			rtl_start_rx(tp);
936162306a36Sopenharmony_ci			tasklet_enable(&tp->tx_tl);
936262306a36Sopenharmony_ci			napi_enable(&tp->napi);
936362306a36Sopenharmony_ci			rtl8152_set_rx_mode(dev);
936462306a36Sopenharmony_ci			netif_wake_queue(dev);
936562306a36Sopenharmony_ci		}
936662306a36Sopenharmony_ci	}
936762306a36Sopenharmony_ci
936862306a36Sopenharmony_ci	mutex_unlock(&tp->control);
936962306a36Sopenharmony_ci
937062306a36Sopenharmony_ci	usb_autopm_put_interface(tp->intf);
937162306a36Sopenharmony_ci
937262306a36Sopenharmony_ci	return ret;
937362306a36Sopenharmony_ci}
937462306a36Sopenharmony_ci
937562306a36Sopenharmony_cistatic const struct net_device_ops rtl8152_netdev_ops = {
937662306a36Sopenharmony_ci	.ndo_open		= rtl8152_open,
937762306a36Sopenharmony_ci	.ndo_stop		= rtl8152_close,
937862306a36Sopenharmony_ci	.ndo_eth_ioctl		= rtl8152_ioctl,
937962306a36Sopenharmony_ci	.ndo_start_xmit		= rtl8152_start_xmit,
938062306a36Sopenharmony_ci	.ndo_tx_timeout		= rtl8152_tx_timeout,
938162306a36Sopenharmony_ci	.ndo_set_features	= rtl8152_set_features,
938262306a36Sopenharmony_ci	.ndo_set_rx_mode	= rtl8152_set_rx_mode,
938362306a36Sopenharmony_ci	.ndo_set_mac_address	= rtl8152_set_mac_address,
938462306a36Sopenharmony_ci	.ndo_change_mtu		= rtl8152_change_mtu,
938562306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
938662306a36Sopenharmony_ci	.ndo_features_check	= rtl8152_features_check,
938762306a36Sopenharmony_ci};
938862306a36Sopenharmony_ci
938962306a36Sopenharmony_cistatic void rtl8152_unload(struct r8152 *tp)
939062306a36Sopenharmony_ci{
939162306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
939262306a36Sopenharmony_ci		return;
939362306a36Sopenharmony_ci
939462306a36Sopenharmony_ci	if (tp->version != RTL_VER_01)
939562306a36Sopenharmony_ci		r8152_power_cut_en(tp, true);
939662306a36Sopenharmony_ci}
939762306a36Sopenharmony_ci
939862306a36Sopenharmony_cistatic void rtl8153_unload(struct r8152 *tp)
939962306a36Sopenharmony_ci{
940062306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
940162306a36Sopenharmony_ci		return;
940262306a36Sopenharmony_ci
940362306a36Sopenharmony_ci	r8153_power_cut_en(tp, false);
940462306a36Sopenharmony_ci}
940562306a36Sopenharmony_ci
940662306a36Sopenharmony_cistatic void rtl8153b_unload(struct r8152 *tp)
940762306a36Sopenharmony_ci{
940862306a36Sopenharmony_ci	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
940962306a36Sopenharmony_ci		return;
941062306a36Sopenharmony_ci
941162306a36Sopenharmony_ci	r8153b_power_cut_en(tp, false);
941262306a36Sopenharmony_ci}
941362306a36Sopenharmony_ci
941462306a36Sopenharmony_cistatic int rtl_ops_init(struct r8152 *tp)
941562306a36Sopenharmony_ci{
941662306a36Sopenharmony_ci	struct rtl_ops *ops = &tp->rtl_ops;
941762306a36Sopenharmony_ci	int ret = 0;
941862306a36Sopenharmony_ci
941962306a36Sopenharmony_ci	switch (tp->version) {
942062306a36Sopenharmony_ci	case RTL_VER_01:
942162306a36Sopenharmony_ci	case RTL_VER_02:
942262306a36Sopenharmony_ci	case RTL_VER_07:
942362306a36Sopenharmony_ci		ops->init		= r8152b_init;
942462306a36Sopenharmony_ci		ops->enable		= rtl8152_enable;
942562306a36Sopenharmony_ci		ops->disable		= rtl8152_disable;
942662306a36Sopenharmony_ci		ops->up			= rtl8152_up;
942762306a36Sopenharmony_ci		ops->down		= rtl8152_down;
942862306a36Sopenharmony_ci		ops->unload		= rtl8152_unload;
942962306a36Sopenharmony_ci		ops->eee_get		= r8152_get_eee;
943062306a36Sopenharmony_ci		ops->eee_set		= r8152_set_eee;
943162306a36Sopenharmony_ci		ops->in_nway		= rtl8152_in_nway;
943262306a36Sopenharmony_ci		ops->hw_phy_cfg		= r8152b_hw_phy_cfg;
943362306a36Sopenharmony_ci		ops->autosuspend_en	= rtl_runtime_suspend_enable;
943462306a36Sopenharmony_ci		tp->rx_buf_sz		= 16 * 1024;
943562306a36Sopenharmony_ci		tp->eee_en		= true;
943662306a36Sopenharmony_ci		tp->eee_adv		= MDIO_EEE_100TX;
943762306a36Sopenharmony_ci		break;
943862306a36Sopenharmony_ci
943962306a36Sopenharmony_ci	case RTL_VER_03:
944062306a36Sopenharmony_ci	case RTL_VER_04:
944162306a36Sopenharmony_ci	case RTL_VER_05:
944262306a36Sopenharmony_ci	case RTL_VER_06:
944362306a36Sopenharmony_ci		ops->init		= r8153_init;
944462306a36Sopenharmony_ci		ops->enable		= rtl8153_enable;
944562306a36Sopenharmony_ci		ops->disable		= rtl8153_disable;
944662306a36Sopenharmony_ci		ops->up			= rtl8153_up;
944762306a36Sopenharmony_ci		ops->down		= rtl8153_down;
944862306a36Sopenharmony_ci		ops->unload		= rtl8153_unload;
944962306a36Sopenharmony_ci		ops->eee_get		= r8153_get_eee;
945062306a36Sopenharmony_ci		ops->eee_set		= r8152_set_eee;
945162306a36Sopenharmony_ci		ops->in_nway		= rtl8153_in_nway;
945262306a36Sopenharmony_ci		ops->hw_phy_cfg		= r8153_hw_phy_cfg;
945362306a36Sopenharmony_ci		ops->autosuspend_en	= rtl8153_runtime_enable;
945462306a36Sopenharmony_ci		ops->change_mtu		= rtl8153_change_mtu;
945562306a36Sopenharmony_ci		if (tp->udev->speed < USB_SPEED_SUPER)
945662306a36Sopenharmony_ci			tp->rx_buf_sz	= 16 * 1024;
945762306a36Sopenharmony_ci		else
945862306a36Sopenharmony_ci			tp->rx_buf_sz	= 32 * 1024;
945962306a36Sopenharmony_ci		tp->eee_en		= true;
946062306a36Sopenharmony_ci		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
946162306a36Sopenharmony_ci		break;
946262306a36Sopenharmony_ci
946362306a36Sopenharmony_ci	case RTL_VER_08:
946462306a36Sopenharmony_ci	case RTL_VER_09:
946562306a36Sopenharmony_ci		ops->init		= r8153b_init;
946662306a36Sopenharmony_ci		ops->enable		= rtl8153_enable;
946762306a36Sopenharmony_ci		ops->disable		= rtl8153_disable;
946862306a36Sopenharmony_ci		ops->up			= rtl8153b_up;
946962306a36Sopenharmony_ci		ops->down		= rtl8153b_down;
947062306a36Sopenharmony_ci		ops->unload		= rtl8153b_unload;
947162306a36Sopenharmony_ci		ops->eee_get		= r8153_get_eee;
947262306a36Sopenharmony_ci		ops->eee_set		= r8152_set_eee;
947362306a36Sopenharmony_ci		ops->in_nway		= rtl8153_in_nway;
947462306a36Sopenharmony_ci		ops->hw_phy_cfg		= r8153b_hw_phy_cfg;
947562306a36Sopenharmony_ci		ops->autosuspend_en	= rtl8153b_runtime_enable;
947662306a36Sopenharmony_ci		ops->change_mtu		= rtl8153_change_mtu;
947762306a36Sopenharmony_ci		tp->rx_buf_sz		= 32 * 1024;
947862306a36Sopenharmony_ci		tp->eee_en		= true;
947962306a36Sopenharmony_ci		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
948062306a36Sopenharmony_ci		break;
948162306a36Sopenharmony_ci
948262306a36Sopenharmony_ci	case RTL_VER_11:
948362306a36Sopenharmony_ci		tp->eee_en		= true;
948462306a36Sopenharmony_ci		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
948562306a36Sopenharmony_ci		fallthrough;
948662306a36Sopenharmony_ci	case RTL_VER_10:
948762306a36Sopenharmony_ci		ops->init		= r8156_init;
948862306a36Sopenharmony_ci		ops->enable		= rtl8156_enable;
948962306a36Sopenharmony_ci		ops->disable		= rtl8156_disable;
949062306a36Sopenharmony_ci		ops->up			= rtl8156_up;
949162306a36Sopenharmony_ci		ops->down		= rtl8156_down;
949262306a36Sopenharmony_ci		ops->unload		= rtl8153_unload;
949362306a36Sopenharmony_ci		ops->eee_get		= r8153_get_eee;
949462306a36Sopenharmony_ci		ops->eee_set		= r8152_set_eee;
949562306a36Sopenharmony_ci		ops->in_nway		= rtl8153_in_nway;
949662306a36Sopenharmony_ci		ops->hw_phy_cfg		= r8156_hw_phy_cfg;
949762306a36Sopenharmony_ci		ops->autosuspend_en	= rtl8156_runtime_enable;
949862306a36Sopenharmony_ci		ops->change_mtu		= rtl8156_change_mtu;
949962306a36Sopenharmony_ci		tp->rx_buf_sz		= 48 * 1024;
950062306a36Sopenharmony_ci		tp->support_2500full	= 1;
950162306a36Sopenharmony_ci		break;
950262306a36Sopenharmony_ci
950362306a36Sopenharmony_ci	case RTL_VER_12:
950462306a36Sopenharmony_ci	case RTL_VER_13:
950562306a36Sopenharmony_ci		tp->support_2500full	= 1;
950662306a36Sopenharmony_ci		fallthrough;
950762306a36Sopenharmony_ci	case RTL_VER_15:
950862306a36Sopenharmony_ci		tp->eee_en		= true;
950962306a36Sopenharmony_ci		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
951062306a36Sopenharmony_ci		ops->init		= r8156b_init;
951162306a36Sopenharmony_ci		ops->enable		= rtl8156b_enable;
951262306a36Sopenharmony_ci		ops->disable		= rtl8153_disable;
951362306a36Sopenharmony_ci		ops->up			= rtl8156_up;
951462306a36Sopenharmony_ci		ops->down		= rtl8156_down;
951562306a36Sopenharmony_ci		ops->unload		= rtl8153_unload;
951662306a36Sopenharmony_ci		ops->eee_get		= r8153_get_eee;
951762306a36Sopenharmony_ci		ops->eee_set		= r8152_set_eee;
951862306a36Sopenharmony_ci		ops->in_nway		= rtl8153_in_nway;
951962306a36Sopenharmony_ci		ops->hw_phy_cfg		= r8156b_hw_phy_cfg;
952062306a36Sopenharmony_ci		ops->autosuspend_en	= rtl8156_runtime_enable;
952162306a36Sopenharmony_ci		ops->change_mtu		= rtl8156_change_mtu;
952262306a36Sopenharmony_ci		tp->rx_buf_sz		= 48 * 1024;
952362306a36Sopenharmony_ci		break;
952462306a36Sopenharmony_ci
952562306a36Sopenharmony_ci	case RTL_VER_14:
952662306a36Sopenharmony_ci		ops->init		= r8153c_init;
952762306a36Sopenharmony_ci		ops->enable		= rtl8153_enable;
952862306a36Sopenharmony_ci		ops->disable		= rtl8153_disable;
952962306a36Sopenharmony_ci		ops->up			= rtl8153c_up;
953062306a36Sopenharmony_ci		ops->down		= rtl8153b_down;
953162306a36Sopenharmony_ci		ops->unload		= rtl8153_unload;
953262306a36Sopenharmony_ci		ops->eee_get		= r8153_get_eee;
953362306a36Sopenharmony_ci		ops->eee_set		= r8152_set_eee;
953462306a36Sopenharmony_ci		ops->in_nway		= rtl8153_in_nway;
953562306a36Sopenharmony_ci		ops->hw_phy_cfg		= r8153c_hw_phy_cfg;
953662306a36Sopenharmony_ci		ops->autosuspend_en	= rtl8153c_runtime_enable;
953762306a36Sopenharmony_ci		ops->change_mtu		= rtl8153c_change_mtu;
953862306a36Sopenharmony_ci		tp->rx_buf_sz		= 32 * 1024;
953962306a36Sopenharmony_ci		tp->eee_en		= true;
954062306a36Sopenharmony_ci		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
954162306a36Sopenharmony_ci		break;
954262306a36Sopenharmony_ci
954362306a36Sopenharmony_ci	default:
954462306a36Sopenharmony_ci		ret = -ENODEV;
954562306a36Sopenharmony_ci		dev_err(&tp->intf->dev, "Unknown Device\n");
954662306a36Sopenharmony_ci		break;
954762306a36Sopenharmony_ci	}
954862306a36Sopenharmony_ci
954962306a36Sopenharmony_ci	return ret;
955062306a36Sopenharmony_ci}
955162306a36Sopenharmony_ci
955262306a36Sopenharmony_ci#define FIRMWARE_8153A_2	"rtl_nic/rtl8153a-2.fw"
955362306a36Sopenharmony_ci#define FIRMWARE_8153A_3	"rtl_nic/rtl8153a-3.fw"
955462306a36Sopenharmony_ci#define FIRMWARE_8153A_4	"rtl_nic/rtl8153a-4.fw"
955562306a36Sopenharmony_ci#define FIRMWARE_8153B_2	"rtl_nic/rtl8153b-2.fw"
955662306a36Sopenharmony_ci#define FIRMWARE_8153C_1	"rtl_nic/rtl8153c-1.fw"
955762306a36Sopenharmony_ci#define FIRMWARE_8156A_2	"rtl_nic/rtl8156a-2.fw"
955862306a36Sopenharmony_ci#define FIRMWARE_8156B_2	"rtl_nic/rtl8156b-2.fw"
955962306a36Sopenharmony_ci
956062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153A_2);
956162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153A_3);
956262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153A_4);
956362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153B_2);
956462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153C_1);
956562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8156A_2);
956662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8156B_2);
956762306a36Sopenharmony_ci
956862306a36Sopenharmony_cistatic int rtl_fw_init(struct r8152 *tp)
956962306a36Sopenharmony_ci{
957062306a36Sopenharmony_ci	struct rtl_fw *rtl_fw = &tp->rtl_fw;
957162306a36Sopenharmony_ci
957262306a36Sopenharmony_ci	switch (tp->version) {
957362306a36Sopenharmony_ci	case RTL_VER_04:
957462306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8153A_2;
957562306a36Sopenharmony_ci		rtl_fw->pre_fw		= r8153_pre_firmware_1;
957662306a36Sopenharmony_ci		rtl_fw->post_fw		= r8153_post_firmware_1;
957762306a36Sopenharmony_ci		break;
957862306a36Sopenharmony_ci	case RTL_VER_05:
957962306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8153A_3;
958062306a36Sopenharmony_ci		rtl_fw->pre_fw		= r8153_pre_firmware_2;
958162306a36Sopenharmony_ci		rtl_fw->post_fw		= r8153_post_firmware_2;
958262306a36Sopenharmony_ci		break;
958362306a36Sopenharmony_ci	case RTL_VER_06:
958462306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8153A_4;
958562306a36Sopenharmony_ci		rtl_fw->post_fw		= r8153_post_firmware_3;
958662306a36Sopenharmony_ci		break;
958762306a36Sopenharmony_ci	case RTL_VER_09:
958862306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8153B_2;
958962306a36Sopenharmony_ci		rtl_fw->pre_fw		= r8153b_pre_firmware_1;
959062306a36Sopenharmony_ci		rtl_fw->post_fw		= r8153b_post_firmware_1;
959162306a36Sopenharmony_ci		break;
959262306a36Sopenharmony_ci	case RTL_VER_11:
959362306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8156A_2;
959462306a36Sopenharmony_ci		rtl_fw->post_fw		= r8156a_post_firmware_1;
959562306a36Sopenharmony_ci		break;
959662306a36Sopenharmony_ci	case RTL_VER_13:
959762306a36Sopenharmony_ci	case RTL_VER_15:
959862306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8156B_2;
959962306a36Sopenharmony_ci		break;
960062306a36Sopenharmony_ci	case RTL_VER_14:
960162306a36Sopenharmony_ci		rtl_fw->fw_name		= FIRMWARE_8153C_1;
960262306a36Sopenharmony_ci		rtl_fw->pre_fw		= r8153b_pre_firmware_1;
960362306a36Sopenharmony_ci		rtl_fw->post_fw		= r8153c_post_firmware_1;
960462306a36Sopenharmony_ci		break;
960562306a36Sopenharmony_ci	default:
960662306a36Sopenharmony_ci		break;
960762306a36Sopenharmony_ci	}
960862306a36Sopenharmony_ci
960962306a36Sopenharmony_ci	return 0;
961062306a36Sopenharmony_ci}
961162306a36Sopenharmony_ci
961262306a36Sopenharmony_cistatic u8 __rtl_get_hw_ver(struct usb_device *udev)
961362306a36Sopenharmony_ci{
961462306a36Sopenharmony_ci	u32 ocp_data = 0;
961562306a36Sopenharmony_ci	__le32 *tmp;
961662306a36Sopenharmony_ci	u8 version;
961762306a36Sopenharmony_ci	int ret;
961862306a36Sopenharmony_ci	int i;
961962306a36Sopenharmony_ci
962062306a36Sopenharmony_ci	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
962162306a36Sopenharmony_ci	if (!tmp)
962262306a36Sopenharmony_ci		return 0;
962362306a36Sopenharmony_ci
962462306a36Sopenharmony_ci	/* Retry up to 3 times in case there is a transitory error. We do this
962562306a36Sopenharmony_ci	 * since retrying a read of the version is always safe and this
962662306a36Sopenharmony_ci	 * function doesn't take advantage of r8152_control_msg().
962762306a36Sopenharmony_ci	 */
962862306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
962962306a36Sopenharmony_ci		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
963062306a36Sopenharmony_ci				      RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
963162306a36Sopenharmony_ci				      PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp),
963262306a36Sopenharmony_ci				      USB_CTRL_GET_TIMEOUT);
963362306a36Sopenharmony_ci		if (ret > 0) {
963462306a36Sopenharmony_ci			ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK;
963562306a36Sopenharmony_ci			break;
963662306a36Sopenharmony_ci		}
963762306a36Sopenharmony_ci	}
963862306a36Sopenharmony_ci
963962306a36Sopenharmony_ci	if (i != 0 && ret > 0)
964062306a36Sopenharmony_ci		dev_warn(&udev->dev, "Needed %d retries to read version\n", i);
964162306a36Sopenharmony_ci
964262306a36Sopenharmony_ci	kfree(tmp);
964362306a36Sopenharmony_ci
964462306a36Sopenharmony_ci	switch (ocp_data) {
964562306a36Sopenharmony_ci	case 0x4c00:
964662306a36Sopenharmony_ci		version = RTL_VER_01;
964762306a36Sopenharmony_ci		break;
964862306a36Sopenharmony_ci	case 0x4c10:
964962306a36Sopenharmony_ci		version = RTL_VER_02;
965062306a36Sopenharmony_ci		break;
965162306a36Sopenharmony_ci	case 0x5c00:
965262306a36Sopenharmony_ci		version = RTL_VER_03;
965362306a36Sopenharmony_ci		break;
965462306a36Sopenharmony_ci	case 0x5c10:
965562306a36Sopenharmony_ci		version = RTL_VER_04;
965662306a36Sopenharmony_ci		break;
965762306a36Sopenharmony_ci	case 0x5c20:
965862306a36Sopenharmony_ci		version = RTL_VER_05;
965962306a36Sopenharmony_ci		break;
966062306a36Sopenharmony_ci	case 0x5c30:
966162306a36Sopenharmony_ci		version = RTL_VER_06;
966262306a36Sopenharmony_ci		break;
966362306a36Sopenharmony_ci	case 0x4800:
966462306a36Sopenharmony_ci		version = RTL_VER_07;
966562306a36Sopenharmony_ci		break;
966662306a36Sopenharmony_ci	case 0x6000:
966762306a36Sopenharmony_ci		version = RTL_VER_08;
966862306a36Sopenharmony_ci		break;
966962306a36Sopenharmony_ci	case 0x6010:
967062306a36Sopenharmony_ci		version = RTL_VER_09;
967162306a36Sopenharmony_ci		break;
967262306a36Sopenharmony_ci	case 0x7010:
967362306a36Sopenharmony_ci		version = RTL_TEST_01;
967462306a36Sopenharmony_ci		break;
967562306a36Sopenharmony_ci	case 0x7020:
967662306a36Sopenharmony_ci		version = RTL_VER_10;
967762306a36Sopenharmony_ci		break;
967862306a36Sopenharmony_ci	case 0x7030:
967962306a36Sopenharmony_ci		version = RTL_VER_11;
968062306a36Sopenharmony_ci		break;
968162306a36Sopenharmony_ci	case 0x7400:
968262306a36Sopenharmony_ci		version = RTL_VER_12;
968362306a36Sopenharmony_ci		break;
968462306a36Sopenharmony_ci	case 0x7410:
968562306a36Sopenharmony_ci		version = RTL_VER_13;
968662306a36Sopenharmony_ci		break;
968762306a36Sopenharmony_ci	case 0x6400:
968862306a36Sopenharmony_ci		version = RTL_VER_14;
968962306a36Sopenharmony_ci		break;
969062306a36Sopenharmony_ci	case 0x7420:
969162306a36Sopenharmony_ci		version = RTL_VER_15;
969262306a36Sopenharmony_ci		break;
969362306a36Sopenharmony_ci	default:
969462306a36Sopenharmony_ci		version = RTL_VER_UNKNOWN;
969562306a36Sopenharmony_ci		dev_info(&udev->dev, "Unknown version 0x%04x\n", ocp_data);
969662306a36Sopenharmony_ci		break;
969762306a36Sopenharmony_ci	}
969862306a36Sopenharmony_ci
969962306a36Sopenharmony_ci	return version;
970062306a36Sopenharmony_ci}
970162306a36Sopenharmony_ci
970262306a36Sopenharmony_ciu8 rtl8152_get_version(struct usb_interface *intf)
970362306a36Sopenharmony_ci{
970462306a36Sopenharmony_ci	u8 version;
970562306a36Sopenharmony_ci
970662306a36Sopenharmony_ci	version = __rtl_get_hw_ver(interface_to_usbdev(intf));
970762306a36Sopenharmony_ci
970862306a36Sopenharmony_ci	dev_dbg(&intf->dev, "Detected version 0x%04x\n", version);
970962306a36Sopenharmony_ci
971062306a36Sopenharmony_ci	return version;
971162306a36Sopenharmony_ci}
971262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rtl8152_get_version);
971362306a36Sopenharmony_ci
971462306a36Sopenharmony_cistatic bool rtl8152_supports_lenovo_macpassthru(struct usb_device *udev)
971562306a36Sopenharmony_ci{
971662306a36Sopenharmony_ci	int parent_vendor_id = le16_to_cpu(udev->parent->descriptor.idVendor);
971762306a36Sopenharmony_ci	int product_id = le16_to_cpu(udev->descriptor.idProduct);
971862306a36Sopenharmony_ci	int vendor_id = le16_to_cpu(udev->descriptor.idVendor);
971962306a36Sopenharmony_ci
972062306a36Sopenharmony_ci	if (vendor_id == VENDOR_ID_LENOVO) {
972162306a36Sopenharmony_ci		switch (product_id) {
972262306a36Sopenharmony_ci		case DEVICE_ID_LENOVO_USB_C_TRAVEL_HUB:
972362306a36Sopenharmony_ci		case DEVICE_ID_THINKPAD_ONELINK_PLUS_DOCK:
972462306a36Sopenharmony_ci		case DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2:
972562306a36Sopenharmony_ci		case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2:
972662306a36Sopenharmony_ci		case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN3:
972762306a36Sopenharmony_ci		case DEVICE_ID_THINKPAD_USB_C_DONGLE:
972862306a36Sopenharmony_ci			return 1;
972962306a36Sopenharmony_ci		}
973062306a36Sopenharmony_ci	} else if (vendor_id == VENDOR_ID_REALTEK && parent_vendor_id == VENDOR_ID_LENOVO) {
973162306a36Sopenharmony_ci		switch (product_id) {
973262306a36Sopenharmony_ci		case 0x8153:
973362306a36Sopenharmony_ci			return 1;
973462306a36Sopenharmony_ci		}
973562306a36Sopenharmony_ci	}
973662306a36Sopenharmony_ci	return 0;
973762306a36Sopenharmony_ci}
973862306a36Sopenharmony_ci
973962306a36Sopenharmony_cistatic int rtl8152_probe_once(struct usb_interface *intf,
974062306a36Sopenharmony_ci			      const struct usb_device_id *id, u8 version)
974162306a36Sopenharmony_ci{
974262306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(intf);
974362306a36Sopenharmony_ci	struct r8152 *tp;
974462306a36Sopenharmony_ci	struct net_device *netdev;
974562306a36Sopenharmony_ci	int ret;
974662306a36Sopenharmony_ci
974762306a36Sopenharmony_ci	usb_reset_device(udev);
974862306a36Sopenharmony_ci	netdev = alloc_etherdev(sizeof(struct r8152));
974962306a36Sopenharmony_ci	if (!netdev) {
975062306a36Sopenharmony_ci		dev_err(&intf->dev, "Out of memory\n");
975162306a36Sopenharmony_ci		return -ENOMEM;
975262306a36Sopenharmony_ci	}
975362306a36Sopenharmony_ci
975462306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &intf->dev);
975562306a36Sopenharmony_ci	tp = netdev_priv(netdev);
975662306a36Sopenharmony_ci	tp->msg_enable = 0x7FFF;
975762306a36Sopenharmony_ci
975862306a36Sopenharmony_ci	tp->udev = udev;
975962306a36Sopenharmony_ci	tp->netdev = netdev;
976062306a36Sopenharmony_ci	tp->intf = intf;
976162306a36Sopenharmony_ci	tp->version = version;
976262306a36Sopenharmony_ci
976362306a36Sopenharmony_ci	tp->pipe_ctrl_in = usb_rcvctrlpipe(udev, 0);
976462306a36Sopenharmony_ci	tp->pipe_ctrl_out = usb_sndctrlpipe(udev, 0);
976562306a36Sopenharmony_ci	tp->pipe_in = usb_rcvbulkpipe(udev, 1);
976662306a36Sopenharmony_ci	tp->pipe_out = usb_sndbulkpipe(udev, 2);
976762306a36Sopenharmony_ci	tp->pipe_intr = usb_rcvintpipe(udev, 3);
976862306a36Sopenharmony_ci
976962306a36Sopenharmony_ci	switch (version) {
977062306a36Sopenharmony_ci	case RTL_VER_01:
977162306a36Sopenharmony_ci	case RTL_VER_02:
977262306a36Sopenharmony_ci	case RTL_VER_07:
977362306a36Sopenharmony_ci		tp->mii.supports_gmii = 0;
977462306a36Sopenharmony_ci		break;
977562306a36Sopenharmony_ci	default:
977662306a36Sopenharmony_ci		tp->mii.supports_gmii = 1;
977762306a36Sopenharmony_ci		break;
977862306a36Sopenharmony_ci	}
977962306a36Sopenharmony_ci
978062306a36Sopenharmony_ci	ret = rtl_ops_init(tp);
978162306a36Sopenharmony_ci	if (ret)
978262306a36Sopenharmony_ci		goto out;
978362306a36Sopenharmony_ci
978462306a36Sopenharmony_ci	rtl_fw_init(tp);
978562306a36Sopenharmony_ci
978662306a36Sopenharmony_ci	mutex_init(&tp->control);
978762306a36Sopenharmony_ci	INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
978862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&tp->hw_phy_work, rtl_hw_phy_work_func_t);
978962306a36Sopenharmony_ci	tasklet_setup(&tp->tx_tl, bottom_half);
979062306a36Sopenharmony_ci	tasklet_disable(&tp->tx_tl);
979162306a36Sopenharmony_ci
979262306a36Sopenharmony_ci	netdev->netdev_ops = &rtl8152_netdev_ops;
979362306a36Sopenharmony_ci	netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
979462306a36Sopenharmony_ci
979562306a36Sopenharmony_ci	netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
979662306a36Sopenharmony_ci			    NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM |
979762306a36Sopenharmony_ci			    NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_RX |
979862306a36Sopenharmony_ci			    NETIF_F_HW_VLAN_CTAG_TX;
979962306a36Sopenharmony_ci	netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
980062306a36Sopenharmony_ci			      NETIF_F_TSO | NETIF_F_FRAGLIST |
980162306a36Sopenharmony_ci			      NETIF_F_IPV6_CSUM | NETIF_F_TSO6 |
980262306a36Sopenharmony_ci			      NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
980362306a36Sopenharmony_ci	netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
980462306a36Sopenharmony_ci				NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
980562306a36Sopenharmony_ci				NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
980662306a36Sopenharmony_ci
980762306a36Sopenharmony_ci	if (tp->version == RTL_VER_01) {
980862306a36Sopenharmony_ci		netdev->features &= ~NETIF_F_RXCSUM;
980962306a36Sopenharmony_ci		netdev->hw_features &= ~NETIF_F_RXCSUM;
981062306a36Sopenharmony_ci	}
981162306a36Sopenharmony_ci
981262306a36Sopenharmony_ci	tp->lenovo_macpassthru = rtl8152_supports_lenovo_macpassthru(udev);
981362306a36Sopenharmony_ci
981462306a36Sopenharmony_ci	if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial &&
981562306a36Sopenharmony_ci	    (!strcmp(udev->serial, "000001000000") ||
981662306a36Sopenharmony_ci	     !strcmp(udev->serial, "000002000000"))) {
981762306a36Sopenharmony_ci		dev_info(&udev->dev, "Dell TB16 Dock, disable RX aggregation");
981862306a36Sopenharmony_ci		tp->dell_tb_rx_agg_bug = 1;
981962306a36Sopenharmony_ci	}
982062306a36Sopenharmony_ci
982162306a36Sopenharmony_ci	netdev->ethtool_ops = &ops;
982262306a36Sopenharmony_ci	netif_set_tso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
982362306a36Sopenharmony_ci
982462306a36Sopenharmony_ci	/* MTU range: 68 - 1500 or 9194 */
982562306a36Sopenharmony_ci	netdev->min_mtu = ETH_MIN_MTU;
982662306a36Sopenharmony_ci	switch (tp->version) {
982762306a36Sopenharmony_ci	case RTL_VER_03:
982862306a36Sopenharmony_ci	case RTL_VER_04:
982962306a36Sopenharmony_ci	case RTL_VER_05:
983062306a36Sopenharmony_ci	case RTL_VER_06:
983162306a36Sopenharmony_ci	case RTL_VER_08:
983262306a36Sopenharmony_ci	case RTL_VER_09:
983362306a36Sopenharmony_ci	case RTL_VER_14:
983462306a36Sopenharmony_ci		netdev->max_mtu = size_to_mtu(9 * 1024);
983562306a36Sopenharmony_ci		break;
983662306a36Sopenharmony_ci	case RTL_VER_10:
983762306a36Sopenharmony_ci	case RTL_VER_11:
983862306a36Sopenharmony_ci		netdev->max_mtu = size_to_mtu(15 * 1024);
983962306a36Sopenharmony_ci		break;
984062306a36Sopenharmony_ci	case RTL_VER_12:
984162306a36Sopenharmony_ci	case RTL_VER_13:
984262306a36Sopenharmony_ci	case RTL_VER_15:
984362306a36Sopenharmony_ci		netdev->max_mtu = size_to_mtu(16 * 1024);
984462306a36Sopenharmony_ci		break;
984562306a36Sopenharmony_ci	case RTL_VER_01:
984662306a36Sopenharmony_ci	case RTL_VER_02:
984762306a36Sopenharmony_ci	case RTL_VER_07:
984862306a36Sopenharmony_ci	default:
984962306a36Sopenharmony_ci		netdev->max_mtu = ETH_DATA_LEN;
985062306a36Sopenharmony_ci		break;
985162306a36Sopenharmony_ci	}
985262306a36Sopenharmony_ci
985362306a36Sopenharmony_ci	tp->mii.dev = netdev;
985462306a36Sopenharmony_ci	tp->mii.mdio_read = read_mii_word;
985562306a36Sopenharmony_ci	tp->mii.mdio_write = write_mii_word;
985662306a36Sopenharmony_ci	tp->mii.phy_id_mask = 0x3f;
985762306a36Sopenharmony_ci	tp->mii.reg_num_mask = 0x1f;
985862306a36Sopenharmony_ci	tp->mii.phy_id = R8152_PHY_ID;
985962306a36Sopenharmony_ci
986062306a36Sopenharmony_ci	tp->autoneg = AUTONEG_ENABLE;
986162306a36Sopenharmony_ci	tp->speed = SPEED_100;
986262306a36Sopenharmony_ci	tp->advertising = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
986362306a36Sopenharmony_ci			  RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
986462306a36Sopenharmony_ci	if (tp->mii.supports_gmii) {
986562306a36Sopenharmony_ci		if (tp->support_2500full &&
986662306a36Sopenharmony_ci		    tp->udev->speed >= USB_SPEED_SUPER) {
986762306a36Sopenharmony_ci			tp->speed = SPEED_2500;
986862306a36Sopenharmony_ci			tp->advertising |= RTL_ADVERTISED_2500_FULL;
986962306a36Sopenharmony_ci		} else {
987062306a36Sopenharmony_ci			tp->speed = SPEED_1000;
987162306a36Sopenharmony_ci		}
987262306a36Sopenharmony_ci		tp->advertising |= RTL_ADVERTISED_1000_FULL;
987362306a36Sopenharmony_ci	}
987462306a36Sopenharmony_ci	tp->duplex = DUPLEX_FULL;
987562306a36Sopenharmony_ci
987662306a36Sopenharmony_ci	tp->rx_copybreak = RTL8152_RXFG_HEADSZ;
987762306a36Sopenharmony_ci	tp->rx_pending = 10 * RTL8152_MAX_RX;
987862306a36Sopenharmony_ci
987962306a36Sopenharmony_ci	intf->needs_remote_wakeup = 1;
988062306a36Sopenharmony_ci
988162306a36Sopenharmony_ci	if (!rtl_can_wakeup(tp))
988262306a36Sopenharmony_ci		__rtl_set_wol(tp, 0);
988362306a36Sopenharmony_ci	else
988462306a36Sopenharmony_ci		tp->saved_wolopts = __rtl_get_wol(tp);
988562306a36Sopenharmony_ci
988662306a36Sopenharmony_ci	tp->rtl_ops.init(tp);
988762306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_USB_RTL8152)
988862306a36Sopenharmony_ci	/* Retry in case request_firmware() is not ready yet. */
988962306a36Sopenharmony_ci	tp->rtl_fw.retry = true;
989062306a36Sopenharmony_ci#endif
989162306a36Sopenharmony_ci	queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
989262306a36Sopenharmony_ci	set_ethernet_addr(tp, false);
989362306a36Sopenharmony_ci
989462306a36Sopenharmony_ci	usb_set_intfdata(intf, tp);
989562306a36Sopenharmony_ci
989662306a36Sopenharmony_ci	netif_napi_add(netdev, &tp->napi, r8152_poll);
989762306a36Sopenharmony_ci
989862306a36Sopenharmony_ci	ret = register_netdev(netdev);
989962306a36Sopenharmony_ci	if (ret != 0) {
990062306a36Sopenharmony_ci		dev_err(&intf->dev, "couldn't register the device\n");
990162306a36Sopenharmony_ci		goto out1;
990262306a36Sopenharmony_ci	}
990362306a36Sopenharmony_ci
990462306a36Sopenharmony_ci	if (tp->saved_wolopts)
990562306a36Sopenharmony_ci		device_set_wakeup_enable(&udev->dev, true);
990662306a36Sopenharmony_ci	else
990762306a36Sopenharmony_ci		device_set_wakeup_enable(&udev->dev, false);
990862306a36Sopenharmony_ci
990962306a36Sopenharmony_ci	/* If we saw a control transfer error while probing then we may
991062306a36Sopenharmony_ci	 * want to try probe() again. Consider this an error.
991162306a36Sopenharmony_ci	 */
991262306a36Sopenharmony_ci	if (test_bit(PROBE_SHOULD_RETRY, &tp->flags))
991362306a36Sopenharmony_ci		goto out2;
991462306a36Sopenharmony_ci
991562306a36Sopenharmony_ci	set_bit(PROBED_WITH_NO_ERRORS, &tp->flags);
991662306a36Sopenharmony_ci	netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
991762306a36Sopenharmony_ci
991862306a36Sopenharmony_ci	return 0;
991962306a36Sopenharmony_ci
992062306a36Sopenharmony_ciout2:
992162306a36Sopenharmony_ci	unregister_netdev(netdev);
992262306a36Sopenharmony_ci
992362306a36Sopenharmony_ciout1:
992462306a36Sopenharmony_ci	tasklet_kill(&tp->tx_tl);
992562306a36Sopenharmony_ci	cancel_delayed_work_sync(&tp->hw_phy_work);
992662306a36Sopenharmony_ci	if (tp->rtl_ops.unload)
992762306a36Sopenharmony_ci		tp->rtl_ops.unload(tp);
992862306a36Sopenharmony_ci	rtl8152_release_firmware(tp);
992962306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
993062306a36Sopenharmony_ciout:
993162306a36Sopenharmony_ci	if (test_bit(PROBE_SHOULD_RETRY, &tp->flags))
993262306a36Sopenharmony_ci		ret = -EAGAIN;
993362306a36Sopenharmony_ci
993462306a36Sopenharmony_ci	free_netdev(netdev);
993562306a36Sopenharmony_ci	return ret;
993662306a36Sopenharmony_ci}
993762306a36Sopenharmony_ci
993862306a36Sopenharmony_ci#define RTL8152_PROBE_TRIES	3
993962306a36Sopenharmony_ci
994062306a36Sopenharmony_cistatic int rtl8152_probe(struct usb_interface *intf,
994162306a36Sopenharmony_ci			 const struct usb_device_id *id)
994262306a36Sopenharmony_ci{
994362306a36Sopenharmony_ci	u8 version;
994462306a36Sopenharmony_ci	int ret;
994562306a36Sopenharmony_ci	int i;
994662306a36Sopenharmony_ci
994762306a36Sopenharmony_ci	if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
994862306a36Sopenharmony_ci		return -ENODEV;
994962306a36Sopenharmony_ci
995062306a36Sopenharmony_ci	if (!rtl_check_vendor_ok(intf))
995162306a36Sopenharmony_ci		return -ENODEV;
995262306a36Sopenharmony_ci
995362306a36Sopenharmony_ci	version = rtl8152_get_version(intf);
995462306a36Sopenharmony_ci	if (version == RTL_VER_UNKNOWN)
995562306a36Sopenharmony_ci		return -ENODEV;
995662306a36Sopenharmony_ci
995762306a36Sopenharmony_ci	for (i = 0; i < RTL8152_PROBE_TRIES; i++) {
995862306a36Sopenharmony_ci		ret = rtl8152_probe_once(intf, id, version);
995962306a36Sopenharmony_ci		if (ret != -EAGAIN)
996062306a36Sopenharmony_ci			break;
996162306a36Sopenharmony_ci	}
996262306a36Sopenharmony_ci	if (ret == -EAGAIN) {
996362306a36Sopenharmony_ci		dev_err(&intf->dev,
996462306a36Sopenharmony_ci			"r8152 failed probe after %d tries; giving up\n", i);
996562306a36Sopenharmony_ci		return -ENODEV;
996662306a36Sopenharmony_ci	}
996762306a36Sopenharmony_ci
996862306a36Sopenharmony_ci	return ret;
996962306a36Sopenharmony_ci}
997062306a36Sopenharmony_ci
997162306a36Sopenharmony_cistatic void rtl8152_disconnect(struct usb_interface *intf)
997262306a36Sopenharmony_ci{
997362306a36Sopenharmony_ci	struct r8152 *tp = usb_get_intfdata(intf);
997462306a36Sopenharmony_ci
997562306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
997662306a36Sopenharmony_ci	if (tp) {
997762306a36Sopenharmony_ci		rtl_set_unplug(tp);
997862306a36Sopenharmony_ci
997962306a36Sopenharmony_ci		unregister_netdev(tp->netdev);
998062306a36Sopenharmony_ci		tasklet_kill(&tp->tx_tl);
998162306a36Sopenharmony_ci		cancel_delayed_work_sync(&tp->hw_phy_work);
998262306a36Sopenharmony_ci		if (tp->rtl_ops.unload)
998362306a36Sopenharmony_ci			tp->rtl_ops.unload(tp);
998462306a36Sopenharmony_ci		rtl8152_release_firmware(tp);
998562306a36Sopenharmony_ci		free_netdev(tp->netdev);
998662306a36Sopenharmony_ci	}
998762306a36Sopenharmony_ci}
998862306a36Sopenharmony_ci
998962306a36Sopenharmony_ci/* table of devices that work with this driver */
999062306a36Sopenharmony_cistatic const struct usb_device_id rtl8152_table[] = {
999162306a36Sopenharmony_ci	/* Realtek */
999262306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_REALTEK, 0x8050) },
999362306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_REALTEK, 0x8053) },
999462306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_REALTEK, 0x8152) },
999562306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_REALTEK, 0x8153) },
999662306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_REALTEK, 0x8155) },
999762306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_REALTEK, 0x8156) },
999862306a36Sopenharmony_ci
999962306a36Sopenharmony_ci	/* Microsoft */
1000062306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab) },
1000162306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6) },
1000262306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927) },
1000362306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0c5e) },
1000462306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101) },
1000562306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x304f) },
1000662306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x3054) },
1000762306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x3062) },
1000862306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x3069) },
1000962306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x3082) },
1001062306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x7205) },
1001162306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x720c) },
1001262306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x7214) },
1001362306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0x721e) },
1001462306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LENOVO,  0xa387) },
1001562306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041) },
1001662306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_NVIDIA,  0x09ff) },
1001762306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_TPLINK,  0x0601) },
1001862306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_DLINK,   0xb301) },
1001962306a36Sopenharmony_ci	{ USB_DEVICE(VENDOR_ID_ASUS,    0x1976) },
1002062306a36Sopenharmony_ci	{}
1002162306a36Sopenharmony_ci};
1002262306a36Sopenharmony_ci
1002362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, rtl8152_table);
1002462306a36Sopenharmony_ci
1002562306a36Sopenharmony_cistatic struct usb_driver rtl8152_driver = {
1002662306a36Sopenharmony_ci	.name =		MODULENAME,
1002762306a36Sopenharmony_ci	.id_table =	rtl8152_table,
1002862306a36Sopenharmony_ci	.probe =	rtl8152_probe,
1002962306a36Sopenharmony_ci	.disconnect =	rtl8152_disconnect,
1003062306a36Sopenharmony_ci	.suspend =	rtl8152_suspend,
1003162306a36Sopenharmony_ci	.resume =	rtl8152_resume,
1003262306a36Sopenharmony_ci	.reset_resume =	rtl8152_reset_resume,
1003362306a36Sopenharmony_ci	.pre_reset =	rtl8152_pre_reset,
1003462306a36Sopenharmony_ci	.post_reset =	rtl8152_post_reset,
1003562306a36Sopenharmony_ci	.supports_autosuspend = 1,
1003662306a36Sopenharmony_ci	.disable_hub_initiated_lpm = 1,
1003762306a36Sopenharmony_ci};
1003862306a36Sopenharmony_ci
1003962306a36Sopenharmony_cistatic int rtl8152_cfgselector_probe(struct usb_device *udev)
1004062306a36Sopenharmony_ci{
1004162306a36Sopenharmony_ci	struct usb_host_config *c;
1004262306a36Sopenharmony_ci	int i, num_configs;
1004362306a36Sopenharmony_ci
1004462306a36Sopenharmony_ci	/* Switch the device to vendor mode, if and only if the vendor mode
1004562306a36Sopenharmony_ci	 * driver supports it.
1004662306a36Sopenharmony_ci	 */
1004762306a36Sopenharmony_ci	if (__rtl_get_hw_ver(udev) == RTL_VER_UNKNOWN)
1004862306a36Sopenharmony_ci		return 0;
1004962306a36Sopenharmony_ci
1005062306a36Sopenharmony_ci	/* The vendor mode is not always config #1, so to find it out. */
1005162306a36Sopenharmony_ci	c = udev->config;
1005262306a36Sopenharmony_ci	num_configs = udev->descriptor.bNumConfigurations;
1005362306a36Sopenharmony_ci	for (i = 0; i < num_configs; (i++, c++)) {
1005462306a36Sopenharmony_ci		struct usb_interface_descriptor	*desc = NULL;
1005562306a36Sopenharmony_ci
1005662306a36Sopenharmony_ci		if (!c->desc.bNumInterfaces)
1005762306a36Sopenharmony_ci			continue;
1005862306a36Sopenharmony_ci		desc = &c->intf_cache[0]->altsetting->desc;
1005962306a36Sopenharmony_ci		if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
1006062306a36Sopenharmony_ci			break;
1006162306a36Sopenharmony_ci	}
1006262306a36Sopenharmony_ci
1006362306a36Sopenharmony_ci	if (i == num_configs)
1006462306a36Sopenharmony_ci		return -ENODEV;
1006562306a36Sopenharmony_ci
1006662306a36Sopenharmony_ci	if (usb_set_configuration(udev, c->desc.bConfigurationValue)) {
1006762306a36Sopenharmony_ci		dev_err(&udev->dev, "Failed to set configuration %d\n",
1006862306a36Sopenharmony_ci			c->desc.bConfigurationValue);
1006962306a36Sopenharmony_ci		return -ENODEV;
1007062306a36Sopenharmony_ci	}
1007162306a36Sopenharmony_ci
1007262306a36Sopenharmony_ci	return 0;
1007362306a36Sopenharmony_ci}
1007462306a36Sopenharmony_ci
1007562306a36Sopenharmony_cistatic struct usb_device_driver rtl8152_cfgselector_driver = {
1007662306a36Sopenharmony_ci	.name =		MODULENAME "-cfgselector",
1007762306a36Sopenharmony_ci	.probe =	rtl8152_cfgselector_probe,
1007862306a36Sopenharmony_ci	.id_table =	rtl8152_table,
1007962306a36Sopenharmony_ci	.generic_subclass = 1,
1008062306a36Sopenharmony_ci	.supports_autosuspend = 1,
1008162306a36Sopenharmony_ci};
1008262306a36Sopenharmony_ci
1008362306a36Sopenharmony_cistatic int __init rtl8152_driver_init(void)
1008462306a36Sopenharmony_ci{
1008562306a36Sopenharmony_ci	int ret;
1008662306a36Sopenharmony_ci
1008762306a36Sopenharmony_ci	ret = usb_register_device_driver(&rtl8152_cfgselector_driver, THIS_MODULE);
1008862306a36Sopenharmony_ci	if (ret)
1008962306a36Sopenharmony_ci		return ret;
1009062306a36Sopenharmony_ci	return usb_register(&rtl8152_driver);
1009162306a36Sopenharmony_ci}
1009262306a36Sopenharmony_ci
1009362306a36Sopenharmony_cistatic void __exit rtl8152_driver_exit(void)
1009462306a36Sopenharmony_ci{
1009562306a36Sopenharmony_ci	usb_deregister(&rtl8152_driver);
1009662306a36Sopenharmony_ci	usb_deregister_device_driver(&rtl8152_cfgselector_driver);
1009762306a36Sopenharmony_ci}
1009862306a36Sopenharmony_ci
1009962306a36Sopenharmony_cimodule_init(rtl8152_driver_init);
1010062306a36Sopenharmony_cimodule_exit(rtl8152_driver_exit);
1010162306a36Sopenharmony_ci
1010262306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
1010362306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
1010462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1010562306a36Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION);
10106