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