mirror of
https://github.com/sakumisu/CherryUSB.git
synced 2025-05-09 00:21:44 +08:00
2281 lines
65 KiB
C
2281 lines
65 KiB
C
/*
|
|
* Copyright (c) 2024, sakumisu
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include "usbh_core.h"
|
|
#include "usbh_rtl8152.h"
|
|
|
|
#undef USB_DBG_TAG
|
|
#define USB_DBG_TAG "rtl8152"
|
|
#include "usb_log.h"
|
|
|
|
#define DEV_FORMAT "/dev/rtl8152"
|
|
|
|
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_rx_buffer[CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE];
|
|
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_tx_buffer[CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE];
|
|
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_inttx_buffer[2];
|
|
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_buf[32];
|
|
|
|
static struct usbh_rtl8152 g_rtl8152_class;
|
|
|
|
#define RTL8152_REQ_GET_REGS 0x05
|
|
#define RTL8152_REQ_SET_REGS 0x05
|
|
|
|
#define BYTE_EN_DWORD 0xff
|
|
#define BYTE_EN_WORD 0x33
|
|
#define BYTE_EN_BYTE 0x11
|
|
#define BYTE_EN_SIX_BYTES 0x3f
|
|
#define BYTE_EN_START_MASK 0x0f
|
|
#define BYTE_EN_END_MASK 0xf0
|
|
|
|
#define MCU_TYPE_PLA 0x0100
|
|
#define MCU_TYPE_USB 0x0000
|
|
|
|
/* Define these values to match your device */
|
|
#define VENDOR_ID_REALTEK 0x0bda
|
|
#define VENDOR_ID_MICROSOFT 0x045e
|
|
#define VENDOR_ID_SAMSUNG 0x04e8
|
|
#define VENDOR_ID_LENOVO 0x17ef
|
|
#define VENDOR_ID_LINKSYS 0x13b1
|
|
#define VENDOR_ID_NVIDIA 0x0955
|
|
#define VENDOR_ID_TPLINK 0x2357
|
|
#define VENDOR_ID_DLINK 0x2001
|
|
#define VENDOR_ID_ASUS 0x0b05
|
|
|
|
#define R8152_PHY_ID 32
|
|
|
|
#define PLA_IDR 0xc000
|
|
#define PLA_RCR 0xc010
|
|
#define PLA_RCR1 0xc012
|
|
#define PLA_RMS 0xc016
|
|
#define PLA_RXFIFO_CTRL0 0xc0a0
|
|
#define PLA_RXFIFO_FULL 0xc0a2
|
|
#define PLA_RXFIFO_CTRL1 0xc0a4
|
|
#define PLA_RX_FIFO_FULL 0xc0a6
|
|
#define PLA_RXFIFO_CTRL2 0xc0a8
|
|
#define PLA_RX_FIFO_EMPTY 0xc0aa
|
|
#define PLA_DMY_REG0 0xc0b0
|
|
#define PLA_FMC 0xc0b4
|
|
#define PLA_CFG_WOL 0xc0b6
|
|
#define PLA_TEREDO_CFG 0xc0bc
|
|
#define PLA_TEREDO_WAKE_BASE 0xc0c4
|
|
#define PLA_MAR 0xcd00
|
|
#define PLA_BACKUP 0xd000
|
|
#define PLA_BDC_CR 0xd1a0
|
|
#define PLA_TEREDO_TIMER 0xd2cc
|
|
#define PLA_REALWOW_TIMER 0xd2e8
|
|
#define PLA_UPHY_TIMER 0xd388
|
|
#define PLA_SUSPEND_FLAG 0xd38a
|
|
#define PLA_INDICATE_FALG 0xd38c
|
|
#define PLA_MACDBG_PRE 0xd38c /* RTL_VER_04 only */
|
|
#define PLA_MACDBG_POST 0xd38e /* RTL_VER_04 only */
|
|
#define PLA_EXTRA_STATUS 0xd398
|
|
#define PLA_GPHY_CTRL 0xd3ae
|
|
#define PLA_POL_GPIO_CTRL 0xdc6a
|
|
#define PLA_EFUSE_DATA 0xdd00
|
|
#define PLA_EFUSE_CMD 0xdd02
|
|
#define PLA_LEDSEL 0xdd90
|
|
#define PLA_LED_FEATURE 0xdd92
|
|
#define PLA_PHYAR 0xde00
|
|
#define PLA_BOOT_CTRL 0xe004
|
|
#define PLA_LWAKE_CTRL_REG 0xe007
|
|
#define PLA_GPHY_INTR_IMR 0xe022
|
|
#define PLA_EEE_CR 0xe040
|
|
#define PLA_EEE_TXTWSYS 0xe04c
|
|
#define PLA_EEE_TXTWSYS_2P5G 0xe058
|
|
#define PLA_EEEP_CR 0xe080
|
|
#define PLA_MAC_PWR_CTRL 0xe0c0
|
|
#define PLA_MAC_PWR_CTRL2 0xe0ca
|
|
#define PLA_MAC_PWR_CTRL3 0xe0cc
|
|
#define PLA_MAC_PWR_CTRL4 0xe0ce
|
|
#define PLA_WDT6_CTRL 0xe428
|
|
#define PLA_TCR0 0xe610
|
|
#define PLA_TCR1 0xe612
|
|
#define PLA_MTPS 0xe615
|
|
#define PLA_TXFIFO_CTRL 0xe618
|
|
#define PLA_TXFIFO_FULL 0xe61a
|
|
#define PLA_RSTTALLY 0xe800
|
|
#define PLA_CR 0xe813
|
|
#define PLA_CRWECR 0xe81c
|
|
#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */
|
|
#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */
|
|
#define PLA_CONFIG5 0xe822
|
|
#define PLA_PHY_PWR 0xe84c
|
|
#define PLA_OOB_CTRL 0xe84f
|
|
#define PLA_CPCR 0xe854
|
|
#define PLA_MISC_0 0xe858
|
|
#define PLA_MISC_1 0xe85a
|
|
#define PLA_OCP_GPHY_BASE 0xe86c
|
|
#define PLA_TALLYCNT 0xe890
|
|
#define PLA_SFF_STS_7 0xe8de
|
|
#define PLA_PHYSTATUS 0xe908
|
|
#define PLA_CONFIG6 0xe90a /* CONFIG6 */
|
|
#define PLA_USB_CFG 0xe952
|
|
#define PLA_BP_BA 0xfc26
|
|
#define PLA_BP_0 0xfc28
|
|
#define PLA_BP_1 0xfc2a
|
|
#define PLA_BP_2 0xfc2c
|
|
#define PLA_BP_3 0xfc2e
|
|
#define PLA_BP_4 0xfc30
|
|
#define PLA_BP_5 0xfc32
|
|
#define PLA_BP_6 0xfc34
|
|
#define PLA_BP_7 0xfc36
|
|
#define PLA_BP_EN 0xfc38
|
|
|
|
#define USB_USB2PHY 0xb41e
|
|
#define USB_SSPHYLINK1 0xb426
|
|
#define USB_SSPHYLINK2 0xb428
|
|
#define USB_L1_CTRL 0xb45e
|
|
#define USB_U2P3_CTRL 0xb460
|
|
#define USB_CSR_DUMMY1 0xb464
|
|
#define USB_CSR_DUMMY2 0xb466
|
|
#define USB_DEV_STAT 0xb808
|
|
#define USB_CONNECT_TIMER 0xcbf8
|
|
#define USB_MSC_TIMER 0xcbfc
|
|
#define USB_BURST_SIZE 0xcfc0
|
|
#define USB_FW_FIX_EN0 0xcfca
|
|
#define USB_FW_FIX_EN1 0xcfcc
|
|
#define USB_LPM_CONFIG 0xcfd8
|
|
#define USB_ECM_OPTION 0xcfee
|
|
#define USB_CSTMR 0xcfef /* RTL8153A */
|
|
#define USB_MISC_2 0xcfff
|
|
#define USB_ECM_OP 0xd26b
|
|
#define USB_GPHY_CTRL 0xd284
|
|
#define USB_SPEED_OPTION 0xd32a
|
|
#define USB_FW_CTRL 0xd334 /* RTL8153B */
|
|
#define USB_FC_TIMER 0xd340
|
|
#define USB_USB_CTRL 0xd406
|
|
#define USB_PHY_CTRL 0xd408
|
|
#define USB_TX_AGG 0xd40a
|
|
#define USB_RX_BUF_TH 0xd40c
|
|
#define USB_USB_TIMER 0xd428
|
|
#define USB_RX_EARLY_TIMEOUT 0xd42c
|
|
#define USB_RX_EARLY_SIZE 0xd42e
|
|
#define USB_PM_CTRL_STATUS 0xd432 /* RTL8153A */
|
|
#define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */
|
|
#define USB_TX_DMA 0xd434
|
|
#define USB_UPT_RXDMA_OWN 0xd437
|
|
#define USB_UPHY3_MDCMDIO 0xd480
|
|
#define USB_TOLERANCE 0xd490
|
|
#define USB_LPM_CTRL 0xd41a
|
|
#define USB_BMU_RESET 0xd4b0
|
|
#define USB_BMU_CONFIG 0xd4b4
|
|
#define USB_U1U2_TIMER 0xd4da
|
|
#define USB_FW_TASK 0xd4e8 /* RTL8153B */
|
|
#define USB_RX_AGGR_NUM 0xd4ee
|
|
#define USB_UPS_CTRL 0xd800
|
|
#define USB_POWER_CUT 0xd80a
|
|
#define USB_MISC_0 0xd81a
|
|
#define USB_MISC_1 0xd81f
|
|
#define USB_AFE_CTRL2 0xd824
|
|
#define USB_UPHY_XTAL 0xd826
|
|
#define USB_UPS_CFG 0xd842
|
|
#define USB_UPS_FLAGS 0xd848
|
|
#define USB_WDT1_CTRL 0xe404
|
|
#define USB_WDT11_CTRL 0xe43c
|
|
#define USB_BP_BA PLA_BP_BA
|
|
#define USB_BP_0 PLA_BP_0
|
|
#define USB_BP_1 PLA_BP_1
|
|
#define USB_BP_2 PLA_BP_2
|
|
#define USB_BP_3 PLA_BP_3
|
|
#define USB_BP_4 PLA_BP_4
|
|
#define USB_BP_5 PLA_BP_5
|
|
#define USB_BP_6 PLA_BP_6
|
|
#define USB_BP_7 PLA_BP_7
|
|
#define USB_BP_EN PLA_BP_EN /* RTL8153A */
|
|
#define USB_BP_8 0xfc38 /* RTL8153B */
|
|
#define USB_BP_9 0xfc3a
|
|
#define USB_BP_10 0xfc3c
|
|
#define USB_BP_11 0xfc3e
|
|
#define USB_BP_12 0xfc40
|
|
#define USB_BP_13 0xfc42
|
|
#define USB_BP_14 0xfc44
|
|
#define USB_BP_15 0xfc46
|
|
#define USB_BP2_EN 0xfc48
|
|
|
|
/* OCP Registers */
|
|
#define OCP_ALDPS_CONFIG 0x2010
|
|
#define OCP_EEE_CONFIG1 0x2080
|
|
#define OCP_EEE_CONFIG2 0x2092
|
|
#define OCP_EEE_CONFIG3 0x2094
|
|
#define OCP_BASE_MII 0xa400
|
|
#define OCP_EEE_AR 0xa41a
|
|
#define OCP_EEE_DATA 0xa41c
|
|
#define OCP_PHY_STATUS 0xa420
|
|
#define OCP_INTR_EN 0xa424
|
|
#define OCP_NCTL_CFG 0xa42c
|
|
#define OCP_POWER_CFG 0xa430
|
|
#define OCP_EEE_CFG 0xa432
|
|
#define OCP_SRAM_ADDR 0xa436
|
|
#define OCP_SRAM_DATA 0xa438
|
|
#define OCP_DOWN_SPEED 0xa442
|
|
#define OCP_EEE_ABLE 0xa5c4
|
|
#define OCP_EEE_ADV 0xa5d0
|
|
#define OCP_EEE_LPABLE 0xa5d2
|
|
#define OCP_10GBT_CTRL 0xa5d4
|
|
#define OCP_10GBT_STAT 0xa5d6
|
|
#define OCP_EEE_ADV2 0xa6d4
|
|
#define OCP_PHY_STATE 0xa708 /* nway state for 8153 */
|
|
#define OCP_PHY_PATCH_STAT 0xb800
|
|
#define OCP_PHY_PATCH_CMD 0xb820
|
|
#define OCP_PHY_LOCK 0xb82e
|
|
#define OCP_ADC_IOFFSET 0xbcfc
|
|
#define OCP_ADC_CFG 0xbc06
|
|
#define OCP_SYSCLK_CFG 0xc416
|
|
|
|
/* SRAM Register */
|
|
#define SRAM_GREEN_CFG 0x8011
|
|
#define SRAM_LPF_CFG 0x8012
|
|
#define SRAM_GPHY_FW_VER 0x801e
|
|
#define SRAM_10M_AMP1 0x8080
|
|
#define SRAM_10M_AMP2 0x8082
|
|
#define SRAM_IMPEDANCE 0x8084
|
|
#define SRAM_PHY_LOCK 0xb82e
|
|
|
|
/* PLA_RCR */
|
|
#define RCR_AAP 0x00000001
|
|
#define RCR_APM 0x00000002
|
|
#define RCR_AM 0x00000004
|
|
#define RCR_AB 0x00000008
|
|
#define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
|
|
#define SLOT_EN BIT(11)
|
|
|
|
/* PLA_RCR1 */
|
|
#define OUTER_VLAN BIT(7)
|
|
#define INNER_VLAN BIT(6)
|
|
|
|
/* PLA_RXFIFO_CTRL0 */
|
|
#define RXFIFO_THR1_NORMAL 0x00080002
|
|
#define RXFIFO_THR1_OOB 0x01800003
|
|
|
|
/* PLA_RXFIFO_FULL */
|
|
#define RXFIFO_FULL_MASK 0xfff
|
|
|
|
/* PLA_RXFIFO_CTRL1 */
|
|
#define RXFIFO_THR2_FULL 0x00000060
|
|
#define RXFIFO_THR2_HIGH 0x00000038
|
|
#define RXFIFO_THR2_OOB 0x0000004a
|
|
#define RXFIFO_THR2_NORMAL 0x00a0
|
|
|
|
/* PLA_RXFIFO_CTRL2 */
|
|
#define RXFIFO_THR3_FULL 0x00000078
|
|
#define RXFIFO_THR3_HIGH 0x00000048
|
|
#define RXFIFO_THR3_OOB 0x0000005a
|
|
#define RXFIFO_THR3_NORMAL 0x0110
|
|
|
|
/* PLA_TXFIFO_CTRL */
|
|
#define TXFIFO_THR_NORMAL 0x00400008
|
|
#define TXFIFO_THR_NORMAL2 0x01000008
|
|
|
|
/* PLA_DMY_REG0 */
|
|
#define ECM_ALDPS 0x0002
|
|
|
|
/* PLA_FMC */
|
|
#define FMC_FCR_MCU_EN 0x0001
|
|
|
|
/* PLA_EEEP_CR */
|
|
#define EEEP_CR_EEEP_TX 0x0002
|
|
|
|
/* PLA_WDT6_CTRL */
|
|
#define WDT6_SET_MODE 0x0010
|
|
|
|
/* PLA_TCR0 */
|
|
#define TCR0_TX_EMPTY 0x0800
|
|
#define TCR0_AUTO_FIFO 0x0080
|
|
|
|
/* PLA_TCR1 */
|
|
#define VERSION_MASK 0x7cf0
|
|
#define IFG_MASK (BIT(3) | BIT(9) | BIT(8))
|
|
#define IFG_144NS BIT(9)
|
|
#define IFG_96NS (BIT(9) | BIT(8))
|
|
|
|
/* PLA_MTPS */
|
|
#define MTPS_JUMBO (12 * 1024 / 64)
|
|
#define MTPS_DEFAULT (6 * 1024 / 64)
|
|
|
|
/* PLA_RSTTALLY */
|
|
#define TALLY_RESET 0x0001
|
|
|
|
/* PLA_CR */
|
|
#define CR_RST 0x10
|
|
#define CR_RE 0x08
|
|
#define CR_TE 0x04
|
|
|
|
/* PLA_CRWECR */
|
|
#define CRWECR_NORAML 0x00
|
|
#define CRWECR_CONFIG 0xc0
|
|
|
|
/* PLA_OOB_CTRL */
|
|
#define NOW_IS_OOB 0x80
|
|
#define TXFIFO_EMPTY 0x20
|
|
#define RXFIFO_EMPTY 0x10
|
|
#define LINK_LIST_READY 0x02
|
|
#define DIS_MCU_CLROOB 0x01
|
|
#define FIFO_EMPTY (TXFIFO_EMPTY | RXFIFO_EMPTY)
|
|
|
|
/* PLA_MISC_1 */
|
|
#define RXDY_GATED_EN 0x0008
|
|
|
|
/* PLA_SFF_STS_7 */
|
|
#define RE_INIT_LL 0x8000
|
|
#define MCU_BORW_EN 0x4000
|
|
|
|
/* PLA_CPCR */
|
|
#define FLOW_CTRL_EN BIT(0)
|
|
#define CPCR_RX_VLAN 0x0040
|
|
|
|
/* PLA_CFG_WOL */
|
|
#define MAGIC_EN 0x0001
|
|
|
|
/* PLA_TEREDO_CFG */
|
|
#define TEREDO_SEL 0x8000
|
|
#define TEREDO_WAKE_MASK 0x7f00
|
|
#define TEREDO_RS_EVENT_MASK 0x00fe
|
|
#define OOB_TEREDO_EN 0x0001
|
|
|
|
/* PLA_BDC_CR */
|
|
#define ALDPS_PROXY_MODE 0x0001
|
|
|
|
/* PLA_EFUSE_CMD */
|
|
#define EFUSE_READ_CMD BIT(15)
|
|
#define EFUSE_DATA_BIT16 BIT(7)
|
|
|
|
/* PLA_CONFIG34 */
|
|
#define LINK_ON_WAKE_EN 0x0010
|
|
#define LINK_OFF_WAKE_EN 0x0008
|
|
|
|
/* PLA_CONFIG6 */
|
|
#define LANWAKE_CLR_EN BIT(0)
|
|
|
|
/* PLA_USB_CFG */
|
|
#define EN_XG_LIP BIT(1)
|
|
#define EN_G_LIP BIT(2)
|
|
|
|
/* PLA_CONFIG5 */
|
|
#define BWF_EN 0x0040
|
|
#define MWF_EN 0x0020
|
|
#define UWF_EN 0x0010
|
|
#define LAN_WAKE_EN 0x0002
|
|
|
|
/* PLA_LED_FEATURE */
|
|
#define LED_MODE_MASK 0x0700
|
|
|
|
/* PLA_PHY_PWR */
|
|
#define TX_10M_IDLE_EN 0x0080
|
|
#define PFM_PWM_SWITCH 0x0040
|
|
#define TEST_IO_OFF BIT(4)
|
|
|
|
/* PLA_MAC_PWR_CTRL */
|
|
#define D3_CLK_GATED_EN 0x00004000
|
|
#define MCU_CLK_RATIO 0x07010f07
|
|
#define MCU_CLK_RATIO_MASK 0x0f0f0f0f
|
|
#define ALDPS_SPDWN_RATIO 0x0f87
|
|
|
|
/* PLA_MAC_PWR_CTRL2 */
|
|
#define EEE_SPDWN_RATIO 0x8007
|
|
#define MAC_CLK_SPDWN_EN BIT(15)
|
|
#define EEE_SPDWN_RATIO_MASK 0xff
|
|
|
|
/* PLA_MAC_PWR_CTRL3 */
|
|
#define PLA_MCU_SPDWN_EN BIT(14)
|
|
#define PKT_AVAIL_SPDWN_EN 0x0100
|
|
#define SUSPEND_SPDWN_EN 0x0004
|
|
#define U1U2_SPDWN_EN 0x0002
|
|
#define L1_SPDWN_EN 0x0001
|
|
|
|
/* PLA_MAC_PWR_CTRL4 */
|
|
#define PWRSAVE_SPDWN_EN 0x1000
|
|
#define RXDV_SPDWN_EN 0x0800
|
|
#define TX10MIDLE_EN 0x0100
|
|
#define IDLE_SPDWN_EN BIT(6)
|
|
#define TP100_SPDWN_EN 0x0020
|
|
#define TP500_SPDWN_EN 0x0010
|
|
#define TP1000_SPDWN_EN 0x0008
|
|
#define EEE_SPDWN_EN 0x0001
|
|
|
|
/* PLA_GPHY_INTR_IMR */
|
|
#define GPHY_STS_MSK 0x0001
|
|
#define SPEED_DOWN_MSK 0x0002
|
|
#define SPDWN_RXDV_MSK 0x0004
|
|
#define SPDWN_LINKCHG_MSK 0x0008
|
|
|
|
/* PLA_PHYAR */
|
|
#define PHYAR_FLAG 0x80000000
|
|
|
|
/* PLA_EEE_CR */
|
|
#define EEE_RX_EN 0x0001
|
|
#define EEE_TX_EN 0x0002
|
|
|
|
/* PLA_BOOT_CTRL */
|
|
#define AUTOLOAD_DONE 0x0002
|
|
|
|
/* PLA_LWAKE_CTRL_REG */
|
|
#define LANWAKE_PIN BIT(7)
|
|
|
|
/* PLA_SUSPEND_FLAG */
|
|
#define LINK_CHG_EVENT BIT(0)
|
|
|
|
/* PLA_INDICATE_FALG */
|
|
#define UPCOMING_RUNTIME_D3 BIT(0)
|
|
|
|
/* PLA_MACDBG_PRE and PLA_MACDBG_POST */
|
|
#define DEBUG_OE BIT(0)
|
|
#define DEBUG_LTSSM 0x0082
|
|
|
|
/* PLA_EXTRA_STATUS */
|
|
#define CUR_LINK_OK BIT(15)
|
|
#define U3P3_CHECK_EN BIT(7) /* RTL_VER_05 only */
|
|
#define LINK_CHANGE_FLAG BIT(8)
|
|
#define POLL_LINK_CHG BIT(0)
|
|
|
|
/* PLA_GPHY_CTRL */
|
|
#define GPHY_FLASH BIT(1)
|
|
|
|
/* PLA_POL_GPIO_CTRL */
|
|
#define DACK_DET_EN BIT(15)
|
|
#define POL_GPHY_PATCH BIT(4)
|
|
|
|
/* USB_USB2PHY */
|
|
#define USB2PHY_SUSPEND 0x0001
|
|
#define USB2PHY_L1 0x0002
|
|
|
|
/* USB_SSPHYLINK1 */
|
|
#define DELAY_PHY_PWR_CHG BIT(1)
|
|
|
|
/* USB_SSPHYLINK2 */
|
|
#define pwd_dn_scale_mask 0x3ffe
|
|
#define pwd_dn_scale(x) ((x) << 1)
|
|
|
|
/* USB_CSR_DUMMY1 */
|
|
#define DYNAMIC_BURST 0x0001
|
|
|
|
/* USB_CSR_DUMMY2 */
|
|
#define EP4_FULL_FC 0x0001
|
|
|
|
/* USB_DEV_STAT */
|
|
#define STAT_SPEED_MASK 0x0006
|
|
#define STAT_SPEED_HIGH 0x0000
|
|
#define STAT_SPEED_FULL 0x0002
|
|
|
|
/* USB_FW_FIX_EN0 */
|
|
#define FW_FIX_SUSPEND BIT(14)
|
|
|
|
/* USB_FW_FIX_EN1 */
|
|
#define FW_IP_RESET_EN BIT(9)
|
|
|
|
/* USB_LPM_CONFIG */
|
|
#define LPM_U1U2_EN BIT(0)
|
|
|
|
/* USB_TX_AGG */
|
|
#define TX_AGG_MAX_THRESHOLD 0x03
|
|
|
|
/* USB_RX_BUF_TH */
|
|
#define RX_THR_SUPPER 0x0c350180
|
|
#define RX_THR_HIGH 0x7a120180
|
|
#define RX_THR_SLOW 0xffff0180
|
|
#define RX_THR_B 0x00010001
|
|
|
|
/* USB_TX_DMA */
|
|
#define TEST_MODE_DISABLE 0x00000001
|
|
#define TX_SIZE_ADJUST1 0x00000100
|
|
|
|
/* USB_BMU_RESET */
|
|
#define BMU_RESET_EP_IN 0x01
|
|
#define BMU_RESET_EP_OUT 0x02
|
|
|
|
/* USB_BMU_CONFIG */
|
|
#define ACT_ODMA BIT(1)
|
|
|
|
/* USB_UPT_RXDMA_OWN */
|
|
#define OWN_UPDATE BIT(0)
|
|
#define OWN_CLEAR BIT(1)
|
|
|
|
/* USB_FW_TASK */
|
|
#define FC_PATCH_TASK BIT(1)
|
|
|
|
/* USB_RX_AGGR_NUM */
|
|
#define RX_AGGR_NUM_MASK 0x1ff
|
|
|
|
/* USB_UPS_CTRL */
|
|
#define POWER_CUT 0x0100
|
|
|
|
/* USB_PM_CTRL_STATUS */
|
|
#define RESUME_INDICATE 0x0001
|
|
|
|
/* USB_ECM_OPTION */
|
|
#define BYPASS_MAC_RESET BIT(5)
|
|
|
|
/* USB_CSTMR */
|
|
#define FORCE_SUPER BIT(0)
|
|
|
|
/* USB_MISC_2 */
|
|
#define UPS_FORCE_PWR_DOWN BIT(0)
|
|
|
|
/* USB_ECM_OP */
|
|
#define EN_ALL_SPEED BIT(0)
|
|
|
|
/* USB_GPHY_CTRL */
|
|
#define GPHY_PATCH_DONE BIT(2)
|
|
#define BYPASS_FLASH BIT(5)
|
|
#define BACKUP_RESTRORE BIT(6)
|
|
|
|
/* USB_SPEED_OPTION */
|
|
#define RG_PWRDN_EN BIT(8)
|
|
#define ALL_SPEED_OFF BIT(9)
|
|
|
|
/* USB_FW_CTRL */
|
|
#define FLOW_CTRL_PATCH_OPT BIT(1)
|
|
#define AUTO_SPEEDUP BIT(3)
|
|
#define FLOW_CTRL_PATCH_2 BIT(8)
|
|
|
|
/* USB_FC_TIMER */
|
|
#define CTRL_TIMER_EN BIT(15)
|
|
|
|
/* USB_USB_CTRL */
|
|
#define CDC_ECM_EN BIT(3)
|
|
#define RX_AGG_DISABLE 0x0010
|
|
#define RX_ZERO_EN 0x0080
|
|
|
|
/* USB_U2P3_CTRL */
|
|
#define U2P3_ENABLE 0x0001
|
|
#define RX_DETECT8 BIT(3)
|
|
|
|
/* USB_POWER_CUT */
|
|
#define PWR_EN 0x0001
|
|
#define PHASE2_EN 0x0008
|
|
#define UPS_EN BIT(4)
|
|
#define USP_PREWAKE BIT(5)
|
|
|
|
/* USB_MISC_0 */
|
|
#define PCUT_STATUS 0x0001
|
|
|
|
/* USB_RX_EARLY_TIMEOUT */
|
|
#define COALESCE_SUPER 85000U
|
|
#define COALESCE_HIGH 250000U
|
|
#define COALESCE_SLOW 524280U
|
|
|
|
/* USB_WDT1_CTRL */
|
|
#define WTD1_EN BIT(0)
|
|
|
|
/* USB_WDT11_CTRL */
|
|
#define TIMER11_EN 0x0001
|
|
|
|
/* USB_LPM_CTRL */
|
|
/* bit 4 ~ 5: fifo empty boundary */
|
|
#define FIFO_EMPTY_1FB 0x30 /* 0x1fb * 64 = 32448 bytes */
|
|
/* bit 2 ~ 3: LMP timer */
|
|
#define LPM_TIMER_MASK 0x0c
|
|
#define LPM_TIMER_500MS 0x04 /* 500 ms */
|
|
#define LPM_TIMER_500US 0x0c /* 500 us */
|
|
#define ROK_EXIT_LPM 0x02
|
|
|
|
/* USB_AFE_CTRL2 */
|
|
#define SEN_VAL_MASK 0xf800
|
|
#define SEN_VAL_NORMAL 0xa000
|
|
#define SEL_RXIDLE 0x0100
|
|
|
|
/* USB_UPHY_XTAL */
|
|
#define OOBS_POLLING BIT(8)
|
|
|
|
/* USB_UPS_CFG */
|
|
#define SAW_CNT_1MS_MASK 0x0fff
|
|
#define MID_REVERSE BIT(5) /* RTL8156A */
|
|
|
|
/* USB_UPS_FLAGS */
|
|
#define UPS_FLAGS_R_TUNE BIT(0)
|
|
#define UPS_FLAGS_EN_10M_CKDIV BIT(1)
|
|
#define UPS_FLAGS_250M_CKDIV BIT(2)
|
|
#define UPS_FLAGS_EN_ALDPS BIT(3)
|
|
#define UPS_FLAGS_CTAP_SHORT_DIS BIT(4)
|
|
#define UPS_FLAGS_SPEED_MASK (0xf << 16)
|
|
#define ups_flags_speed(x) ((x) << 16)
|
|
#define UPS_FLAGS_EN_EEE BIT(20)
|
|
#define UPS_FLAGS_EN_500M_EEE BIT(21)
|
|
#define UPS_FLAGS_EN_EEE_CKDIV BIT(22)
|
|
#define UPS_FLAGS_EEE_PLLOFF_100 BIT(23)
|
|
#define UPS_FLAGS_EEE_PLLOFF_GIGA BIT(24)
|
|
#define UPS_FLAGS_EEE_CMOD_LV_EN BIT(25)
|
|
#define UPS_FLAGS_EN_GREEN BIT(26)
|
|
#define UPS_FLAGS_EN_FLOW_CTR BIT(27)
|
|
|
|
enum spd_duplex {
|
|
NWAY_10M_HALF,
|
|
NWAY_10M_FULL,
|
|
NWAY_100M_HALF,
|
|
NWAY_100M_FULL,
|
|
NWAY_1000M_FULL,
|
|
FORCE_10M_HALF,
|
|
FORCE_10M_FULL,
|
|
FORCE_100M_HALF,
|
|
FORCE_100M_FULL,
|
|
FORCE_1000M_FULL,
|
|
NWAY_2500M_FULL,
|
|
};
|
|
|
|
/* OCP_ALDPS_CONFIG */
|
|
#define ENPWRSAVE 0x8000
|
|
#define ENPDNPS 0x0200
|
|
#define LINKENA 0x0100
|
|
#define DIS_SDSAVE 0x0010
|
|
|
|
/* OCP_PHY_STATUS */
|
|
#define PHY_STAT_MASK 0x0007
|
|
#define PHY_STAT_EXT_INIT 2
|
|
#define PHY_STAT_LAN_ON 3
|
|
#define PHY_STAT_PWRDN 5
|
|
|
|
/* OCP_INTR_EN */
|
|
#define INTR_SPEED_FORCE BIT(3)
|
|
|
|
/* OCP_NCTL_CFG */
|
|
#define PGA_RETURN_EN BIT(1)
|
|
|
|
/* OCP_POWER_CFG */
|
|
#define EEE_CLKDIV_EN 0x8000
|
|
#define EN_ALDPS 0x0004
|
|
#define EN_10M_PLLOFF 0x0001
|
|
|
|
/* OCP_EEE_CONFIG1 */
|
|
#define RG_TXLPI_MSK_HFDUP 0x8000
|
|
#define RG_MATCLR_EN 0x4000
|
|
#define EEE_10_CAP 0x2000
|
|
#define EEE_NWAY_EN 0x1000
|
|
#define TX_QUIET_EN 0x0200
|
|
#define RX_QUIET_EN 0x0100
|
|
#define sd_rise_time_mask 0x0070
|
|
#define sd_rise_time(x) (MIN(x, 7) << 4) /* bit 4 ~ 6 */
|
|
#define RG_RXLPI_MSK_HFDUP 0x0008
|
|
#define SDFALLTIME 0x0007 /* bit 0 ~ 2 */
|
|
|
|
/* OCP_EEE_CONFIG2 */
|
|
#define RG_LPIHYS_NUM 0x7000 /* bit 12 ~ 15 */
|
|
#define RG_DACQUIET_EN 0x0400
|
|
#define RG_LDVQUIET_EN 0x0200
|
|
#define RG_CKRSEL 0x0020
|
|
#define RG_EEEPRG_EN 0x0010
|
|
|
|
/* OCP_EEE_CONFIG3 */
|
|
#define fast_snr_mask 0xff80
|
|
#define fast_snr(x) (MIN(x, 0x1ff) << 7) /* bit 7 ~ 15 */
|
|
#define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */
|
|
#define MSK_PH 0x0006 /* bit 0 ~ 3 */
|
|
|
|
/* OCP_EEE_AR */
|
|
/* bit[15:14] function */
|
|
#define FUN_ADDR 0x0000
|
|
#define FUN_DATA 0x4000
|
|
/* bit[4:0] device addr */
|
|
|
|
/* OCP_EEE_CFG */
|
|
#define CTAP_SHORT_EN 0x0040
|
|
#define EEE10_EN 0x0010
|
|
|
|
/* OCP_DOWN_SPEED */
|
|
#define EN_EEE_CMODE BIT(14)
|
|
#define EN_EEE_1000 BIT(13)
|
|
#define EN_EEE_100 BIT(12)
|
|
#define EN_10M_CLKDIV BIT(11)
|
|
#define EN_10M_BGOFF 0x0080
|
|
|
|
/* OCP_10GBT_CTRL */
|
|
#define RTL_ADV2_5G_F_R BIT(5) /* Advertise 2.5GBASE-T fast-retrain */
|
|
|
|
/* OCP_PHY_STATE */
|
|
#define TXDIS_STATE 0x01
|
|
#define ABD_STATE 0x02
|
|
|
|
/* OCP_PHY_PATCH_STAT */
|
|
#define PATCH_READY BIT(6)
|
|
|
|
/* OCP_PHY_PATCH_CMD */
|
|
#define PATCH_REQUEST BIT(4)
|
|
|
|
/* OCP_PHY_LOCK */
|
|
#define PATCH_LOCK BIT(0)
|
|
|
|
/* OCP_ADC_CFG */
|
|
#define CKADSEL_L 0x0100
|
|
#define ADC_EN 0x0080
|
|
#define EN_EMI_L 0x0040
|
|
|
|
/* OCP_SYSCLK_CFG */
|
|
#define sysclk_div_expo(x) (MIN(x, 5) << 8)
|
|
#define clk_div_expo(x) (MIN(x, 5) << 4)
|
|
|
|
/* SRAM_GREEN_CFG */
|
|
#define GREEN_ETH_EN BIT(15)
|
|
#define R_TUNE_EN BIT(11)
|
|
|
|
/* SRAM_LPF_CFG */
|
|
#define LPF_AUTO_TUNE 0x8000
|
|
|
|
/* SRAM_10M_AMP1 */
|
|
#define GDAC_IB_UPALL 0x0008
|
|
|
|
/* SRAM_10M_AMP2 */
|
|
#define AMP_DN 0x0200
|
|
|
|
/* SRAM_IMPEDANCE */
|
|
#define RX_DRIVING_MASK 0x6000
|
|
|
|
/* SRAM_PHY_LOCK */
|
|
#define PHY_PATCH_LOCK 0x0001
|
|
|
|
/* MAC PASSTHRU */
|
|
#define AD_MASK 0xfee0
|
|
#define BND_MASK 0x0004
|
|
#define BD_MASK 0x0001
|
|
#define EFUSE 0xcfdb
|
|
#define PASS_THRU_MASK 0x1
|
|
|
|
#define BP4_SUPER_ONLY 0x1578 /* RTL_VER_04 only */
|
|
|
|
enum rtl_register_content {
|
|
_2500bps = BIT(10),
|
|
_1250bps = BIT(9),
|
|
_500bps = BIT(8),
|
|
_tx_flow = BIT(6),
|
|
_rx_flow = BIT(5),
|
|
_1000bps = 0x10,
|
|
_100bps = 0x08,
|
|
_10bps = 0x04,
|
|
LINK_STATUS = 0x02,
|
|
FULL_DUP = 0x01,
|
|
};
|
|
|
|
#define is_speed_2500(_speed) (((_speed) & (_2500bps | LINK_STATUS)) == (_2500bps | LINK_STATUS))
|
|
#define is_flow_control(_speed) (((_speed) & (_tx_flow | _rx_flow)) == (_tx_flow | _rx_flow))
|
|
|
|
#define RTL8152_MAX_TX 4
|
|
#define RTL8152_MAX_RX 10
|
|
#define INTBUFSIZE 2
|
|
#define TX_ALIGN 4
|
|
#define RX_ALIGN 8
|
|
|
|
#define RTL8152_RX_MAX_PENDING 4096
|
|
#define RTL8152_RXFG_HEADSZ 256
|
|
|
|
#define INTR_LINK 0x0004
|
|
|
|
#define VLAN_ETH_HLEN 18
|
|
#define ETH_FCS_LEN 4
|
|
#define VLAN_ETH_FRAME_LEN 1514
|
|
|
|
#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
|
|
#define RTL8153_RMS RTL8153_MAX_PACKET
|
|
#define mtu_to_size(m) ((m) + VLAN_ETH_HLEN + ETH_FCS_LEN)
|
|
#define size_to_mtu(s) ((s)-VLAN_ETH_HLEN - ETH_FCS_LEN)
|
|
#define rx_reserved_size(x) (mtu_to_size(x) + sizeof(struct rx_desc) + RX_ALIGN)
|
|
|
|
struct rx_desc {
|
|
uint32_t opts1;
|
|
#define RD_CRC BIT(15)
|
|
#define RX_LEN_MASK 0x7fff
|
|
|
|
uint32_t opts2;
|
|
#define RD_UDP_CS BIT(23)
|
|
#define RD_TCP_CS BIT(22)
|
|
#define RD_IPV6_CS BIT(20)
|
|
#define RD_IPV4_CS BIT(19)
|
|
|
|
uint32_t opts3;
|
|
#define IPF BIT(23) /* IP checksum fail */
|
|
#define UDPF BIT(22) /* UDP checksum fail */
|
|
#define TCPF BIT(21) /* TCP checksum fail */
|
|
#define RX_VLAN_TAG BIT(16)
|
|
|
|
uint32_t opts4;
|
|
uint32_t opts5;
|
|
uint32_t opts6;
|
|
};
|
|
|
|
struct tx_desc {
|
|
uint32_t opts1;
|
|
#define TX_FS BIT(31) /* First segment of a packet */
|
|
#define TX_LS BIT(30) /* Final segment of a packet */
|
|
#define LGSEND BIT(29)
|
|
#define GTSENDV4 BIT(28)
|
|
#define GTSENDV6 BIT(27)
|
|
#define GTTCPHO_SHIFT 18
|
|
#define GTTCPHO_MAX 0x7fU
|
|
#define TX_LEN_MAX 0x3ffffU
|
|
|
|
uint32_t opts2;
|
|
#define UDP_CS BIT(31) /* Calculate UDP/IP checksum */
|
|
#define TCP_CS BIT(30) /* Calculate TCP/IP checksum */
|
|
#define IPV4_CS BIT(29) /* Calculate IPv4 checksum */
|
|
#define IPV6_CS BIT(28) /* Calculate IPv6 checksum */
|
|
#define MSS_SHIFT 17
|
|
#define MSS_MAX 0x7ffU
|
|
#define TCPHO_SHIFT 17
|
|
#define TCPHO_MAX 0x7ffU
|
|
#define TX_VLAN_TAG BIT(16)
|
|
};
|
|
|
|
enum rtl_version {
|
|
RTL_VER_UNKNOWN = 0,
|
|
RTL_VER_01,
|
|
RTL_VER_02,
|
|
RTL_VER_03,
|
|
RTL_VER_04,
|
|
RTL_VER_05,
|
|
RTL_VER_06,
|
|
RTL_VER_07,
|
|
RTL_VER_08,
|
|
RTL_VER_09,
|
|
|
|
RTL_TEST_01,
|
|
RTL_VER_10,
|
|
RTL_VER_11,
|
|
RTL_VER_12,
|
|
RTL_VER_13,
|
|
RTL_VER_14,
|
|
RTL_VER_15,
|
|
|
|
RTL_VER_MAX
|
|
};
|
|
|
|
/* mii.h */
|
|
/* Generic MII registers. */
|
|
#define MII_BMCR 0x00 /* Basic mode control register */
|
|
#define MII_BMSR 0x01 /* Basic mode status register */
|
|
#define MII_PHYSID1 0x02 /* PHYS ID 1 */
|
|
#define MII_PHYSID2 0x03 /* PHYS ID 2 */
|
|
#define MII_ADVERTISE 0x04 /* Advertisement control reg */
|
|
#define MII_LPA 0x05 /* Link partner ability reg */
|
|
#define MII_EXPANSION 0x06 /* Expansion register */
|
|
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
|
|
#define MII_STAT1000 0x0a /* 1000BASE-T status */
|
|
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
|
|
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
|
|
#define MII_ESTATUS 0x0f /* Extended Status */
|
|
#define MII_DCOUNTER 0x12 /* Disconnect counter */
|
|
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
|
|
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
|
|
#define MII_RERRCOUNTER 0x15 /* Receive error counter */
|
|
#define MII_SREVISION 0x16 /* Silicon revision */
|
|
#define MII_RESV1 0x17 /* Reserved... */
|
|
#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
|
|
#define MII_PHYADDR 0x19 /* PHY address */
|
|
#define MII_RESV2 0x1a /* Reserved... */
|
|
#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
|
|
#define MII_NCONFIG 0x1c /* Network interface config */
|
|
|
|
/* Basic mode control register. */
|
|
#define BMCR_RESV 0x003f /* Unused... */
|
|
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
|
|
#define BMCR_CTST 0x0080 /* Collision test */
|
|
#define BMCR_FULLDPLX 0x0100 /* Full duplex */
|
|
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
|
|
#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */
|
|
#define BMCR_PDOWN 0x0800 /* Enable low power state */
|
|
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
|
|
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
|
|
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
|
|
#define BMCR_RESET 0x8000 /* Reset to default state */
|
|
#define BMCR_SPEED10 0x0000 /* Select 10Mbps */
|
|
|
|
/* Basic mode status register. */
|
|
#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
|
|
#define BMSR_JCD 0x0002 /* Jabber detected */
|
|
#define BMSR_LSTATUS 0x0004 /* Link status */
|
|
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
|
|
#define BMSR_RFAULT 0x0010 /* Remote fault detected */
|
|
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
|
|
#define BMSR_RESV 0x00c0 /* Unused... */
|
|
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
|
|
#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
|
|
#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
|
|
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
|
|
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
|
|
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
|
|
#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
|
|
#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
|
|
|
|
/* Advertisement control register. */
|
|
#define ADVERTISE_SLCT 0x001f /* Selector bits */
|
|
#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
|
|
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
|
|
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
|
|
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
|
|
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
|
|
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
|
|
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
|
|
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
|
|
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
|
|
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
|
|
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
|
|
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
|
|
#define ADVERTISE_RESV 0x1000 /* Unused... */
|
|
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
|
|
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
|
|
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
|
|
|
|
#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
|
|
ADVERTISE_CSMA)
|
|
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
|
|
ADVERTISE_100HALF | ADVERTISE_100FULL)
|
|
|
|
/* 1000BASE-T Control register */
|
|
#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
|
|
#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
|
|
#define CTL1000_AS_MASTER 0x0800
|
|
#define CTL1000_ENABLE_MASTER 0x1000
|
|
|
|
/* ethtool.h */
|
|
/* The forced speed, 10Mb, 100Mb, gigabit. */
|
|
#define SPEED_10 10
|
|
#define SPEED_100 100
|
|
#define SPEED_1000 1000
|
|
|
|
#define SPEED_UNKNOWN -1
|
|
|
|
/* Duplex, half or full. */
|
|
#define DUPLEX_HALF 0x00
|
|
#define DUPLEX_FULL 0x01
|
|
#define DUPLEX_UNKNOWN 0xff
|
|
|
|
/* Enable or disable autonegotiation. */
|
|
#define AUTONEG_DISABLE 0x00
|
|
#define AUTONEG_ENABLE 0x01
|
|
|
|
static int usbh_rtl8152_read_regs(struct usbh_rtl8152 *rtl8152_class,
|
|
uint16_t value,
|
|
uint16_t index,
|
|
uint16_t size,
|
|
void *data)
|
|
{
|
|
struct usb_setup_packet *setup;
|
|
int ret;
|
|
|
|
if (!rtl8152_class || !rtl8152_class->hport) {
|
|
return -USB_ERR_INVAL;
|
|
}
|
|
setup = rtl8152_class->hport->setup;
|
|
|
|
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
|
setup->bRequest = RTL8152_REQ_GET_REGS;
|
|
setup->wValue = value;
|
|
setup->wIndex = index;
|
|
setup->wLength = size;
|
|
|
|
ret = usbh_control_transfer(rtl8152_class->hport, setup, g_rtl8152_buf);
|
|
if (ret < 8) {
|
|
return ret;
|
|
}
|
|
memcpy(data, g_rtl8152_buf, ret - 8);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int usbh_rtl8152_write_regs(struct usbh_rtl8152 *rtl8152_class,
|
|
uint16_t value,
|
|
uint16_t index,
|
|
uint16_t size,
|
|
void *data)
|
|
{
|
|
struct usb_setup_packet *setup;
|
|
|
|
if (!rtl8152_class || !rtl8152_class->hport) {
|
|
return -USB_ERR_INVAL;
|
|
}
|
|
setup = rtl8152_class->hport->setup;
|
|
|
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
|
setup->bRequest = RTL8152_REQ_SET_REGS;
|
|
setup->wValue = value;
|
|
setup->wIndex = index;
|
|
setup->wLength = size;
|
|
|
|
memcpy(g_rtl8152_buf, data, size);
|
|
return usbh_control_transfer(rtl8152_class->hport, setup, g_rtl8152_buf);
|
|
}
|
|
|
|
static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t size,
|
|
void *data, uint16_t type)
|
|
{
|
|
uint16_t limit = 64;
|
|
int ret = 0;
|
|
uint8_t *buf = data;
|
|
|
|
/* both size and indix must be 4 bytes align */
|
|
if ((size & 3) || !size || (index & 3) || !buf)
|
|
return -USB_ERR_INVAL;
|
|
|
|
if ((uint32_t)index + (uint32_t)size > 0xffff)
|
|
return -USB_ERR_INVAL;
|
|
|
|
while (size) {
|
|
if (size > limit) {
|
|
ret = usbh_rtl8152_read_regs(tp, index, type, limit, buf);
|
|
if (ret < 0)
|
|
break;
|
|
|
|
index += limit;
|
|
buf += limit;
|
|
size -= limit;
|
|
} else {
|
|
ret = usbh_rtl8152_read_regs(tp, index, type, size, buf);
|
|
if (ret < 0)
|
|
break;
|
|
|
|
index += size;
|
|
buf += size;
|
|
size = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen,
|
|
uint16_t size, void *data, uint16_t type)
|
|
{
|
|
int ret;
|
|
uint16_t byteen_start, byteen_end, byen;
|
|
uint16_t limit = 512;
|
|
uint8_t *buf = data;
|
|
|
|
/* both size and indix must be 4 bytes align */
|
|
if ((size & 3) || !size || (index & 3) || !buf)
|
|
return -USB_ERR_INVAL;
|
|
|
|
if ((uint32_t)index + (uint32_t)size > 0xffff)
|
|
return -USB_ERR_INVAL;
|
|
|
|
byteen_start = byteen & BYTE_EN_START_MASK;
|
|
byteen_end = byteen & BYTE_EN_END_MASK;
|
|
|
|
byen = byteen_start | (byteen_start << 4);
|
|
|
|
/* Split the first DWORD if the byte_en is not 0xff */
|
|
if (byen != BYTE_EN_DWORD) {
|
|
ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, buf);
|
|
if (ret < 0)
|
|
goto error1;
|
|
|
|
index += 4;
|
|
buf += 4;
|
|
size -= 4;
|
|
}
|
|
|
|
if (size) {
|
|
byen = byteen_end | (byteen_end >> 4);
|
|
|
|
/* Split the last DWORD if the byte_en is not 0xff */
|
|
if (byen != BYTE_EN_DWORD)
|
|
size -= 4;
|
|
|
|
while (size) {
|
|
if (size > limit) {
|
|
ret = usbh_rtl8152_write_regs(tp, index,
|
|
type | BYTE_EN_DWORD,
|
|
limit, buf);
|
|
if (ret < 0)
|
|
goto error1;
|
|
|
|
index += limit;
|
|
buf += limit;
|
|
size -= limit;
|
|
} else {
|
|
ret = usbh_rtl8152_write_regs(tp, index,
|
|
type | BYTE_EN_DWORD,
|
|
size, buf);
|
|
if (ret < 0)
|
|
goto error1;
|
|
|
|
index += size;
|
|
buf += size;
|
|
size = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Set the last DWORD */
|
|
if (byen != BYTE_EN_DWORD)
|
|
ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, buf);
|
|
}
|
|
|
|
error1:
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline int pla_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t size, void *data)
|
|
{
|
|
return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
|
|
}
|
|
|
|
static inline int pla_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen, uint16_t size, void *data)
|
|
{
|
|
return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
|
|
}
|
|
|
|
static inline int usb_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen, uint16_t size, void *data)
|
|
{
|
|
return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
|
|
}
|
|
|
|
static uint32_t ocp_read_dword(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
|
|
{
|
|
uint32_t data;
|
|
|
|
generic_ocp_read(tp, index, sizeof(data), &data, type);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void ocp_write_dword(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index, uint32_t data)
|
|
{
|
|
uint32_t tmp = data;
|
|
|
|
generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
|
|
}
|
|
|
|
static uint16_t ocp_read_word(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
|
|
{
|
|
uint32_t data;
|
|
uint32_t tmp;
|
|
uint16_t byen = BYTE_EN_WORD;
|
|
uint8_t shift = index & 2;
|
|
|
|
index &= ~3;
|
|
byen <<= shift;
|
|
|
|
generic_ocp_read(tp, index, sizeof(tmp), &tmp, type | byen);
|
|
|
|
data = tmp;
|
|
data >>= (shift * 8);
|
|
data &= 0xffff;
|
|
|
|
return (uint16_t)data;
|
|
}
|
|
|
|
static void ocp_write_word(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index, uint32_t data)
|
|
{
|
|
uint32_t mask = 0xffff;
|
|
uint32_t tmp;
|
|
uint16_t byen = BYTE_EN_WORD;
|
|
uint8_t shift = index & 2;
|
|
|
|
data &= mask;
|
|
|
|
if (index & 2) {
|
|
byen <<= shift;
|
|
mask <<= (shift * 8);
|
|
data <<= (shift * 8);
|
|
index &= ~3;
|
|
}
|
|
|
|
tmp = data;
|
|
|
|
generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
|
|
}
|
|
|
|
static uint8_t ocp_read_byte(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
|
|
{
|
|
uint32_t data;
|
|
uint32_t tmp;
|
|
uint8_t shift = index & 3;
|
|
|
|
index &= ~3;
|
|
|
|
generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
|
|
|
|
data = tmp;
|
|
data >>= (shift * 8);
|
|
data &= 0xff;
|
|
|
|
return (uint8_t)data;
|
|
}
|
|
|
|
static void ocp_write_byte(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index, uint32_t data)
|
|
{
|
|
uint32_t mask = 0xff;
|
|
uint32_t tmp;
|
|
uint16_t byen = BYTE_EN_BYTE;
|
|
uint8_t shift = index & 3;
|
|
|
|
data &= mask;
|
|
|
|
if (index & 3) {
|
|
byen <<= shift;
|
|
mask <<= (shift * 8);
|
|
data <<= (shift * 8);
|
|
index &= ~3;
|
|
}
|
|
|
|
tmp = data;
|
|
|
|
generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
|
|
}
|
|
|
|
static uint16_t ocp_reg_read(struct usbh_rtl8152 *tp, uint16_t addr)
|
|
{
|
|
uint16_t ocp_base, ocp_index;
|
|
|
|
ocp_base = addr & 0xf000;
|
|
if (ocp_base != tp->ocp_base) {
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
|
|
tp->ocp_base = ocp_base;
|
|
}
|
|
|
|
ocp_index = (addr & 0x0fff) | 0xb000;
|
|
return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
|
|
}
|
|
|
|
static void ocp_reg_write(struct usbh_rtl8152 *tp, uint16_t addr, uint16_t data)
|
|
{
|
|
uint16_t ocp_base, ocp_index;
|
|
|
|
ocp_base = addr & 0xf000;
|
|
if (ocp_base != tp->ocp_base) {
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
|
|
tp->ocp_base = ocp_base;
|
|
}
|
|
|
|
ocp_index = (addr & 0x0fff) | 0xb000;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
|
|
}
|
|
|
|
static inline void r8152_mdio_write(struct usbh_rtl8152 *tp, uint32_t reg_addr, uint32_t value)
|
|
{
|
|
ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
|
|
}
|
|
|
|
static inline int r8152_mdio_read(struct usbh_rtl8152 *tp, uint32_t reg_addr)
|
|
{
|
|
return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
|
|
}
|
|
|
|
static uint8_t usbh_rtl8152_get_version(struct usbh_rtl8152 *rtl8152_class)
|
|
{
|
|
uint8_t version;
|
|
uint32_t temp;
|
|
uint32_t ocp_data;
|
|
|
|
usbh_rtl8152_read_regs(rtl8152_class, PLA_TCR0, MCU_TYPE_PLA, 4, &temp);
|
|
|
|
ocp_data = (temp >> 16) & VERSION_MASK;
|
|
switch (ocp_data) {
|
|
case 0x4c00:
|
|
version = RTL_VER_01;
|
|
break;
|
|
case 0x4c10:
|
|
version = RTL_VER_02;
|
|
break;
|
|
case 0x5c00:
|
|
version = RTL_VER_03;
|
|
break;
|
|
case 0x5c10:
|
|
version = RTL_VER_04;
|
|
break;
|
|
case 0x5c20:
|
|
version = RTL_VER_05;
|
|
break;
|
|
case 0x5c30:
|
|
version = RTL_VER_06;
|
|
break;
|
|
case 0x4800:
|
|
version = RTL_VER_07;
|
|
break;
|
|
case 0x6000:
|
|
version = RTL_VER_08;
|
|
break;
|
|
case 0x6010:
|
|
version = RTL_VER_09;
|
|
break;
|
|
case 0x7010:
|
|
version = RTL_TEST_01;
|
|
break;
|
|
case 0x7020:
|
|
version = RTL_VER_10;
|
|
break;
|
|
case 0x7030:
|
|
version = RTL_VER_11;
|
|
break;
|
|
case 0x7400:
|
|
version = RTL_VER_12;
|
|
break;
|
|
case 0x7410:
|
|
version = RTL_VER_13;
|
|
break;
|
|
case 0x6400:
|
|
version = RTL_VER_14;
|
|
break;
|
|
case 0x7420:
|
|
version = RTL_VER_15;
|
|
break;
|
|
default:
|
|
version = RTL_VER_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
return version;
|
|
}
|
|
|
|
#define WAKE_PHY (1 << 0)
|
|
#define WAKE_UCAST (1 << 1)
|
|
#define WAKE_MCAST (1 << 2)
|
|
#define WAKE_BCAST (1 << 3)
|
|
#define WAKE_ARP (1 << 4)
|
|
#define WAKE_MAGIC (1 << 5)
|
|
#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
|
|
#define WAKE_FILTER (1 << 7)
|
|
|
|
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
|
|
|
|
static uint32_t __rtl_get_wol(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
uint32_t wolopts = 0;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
|
|
if (ocp_data & LINK_ON_WAKE_EN)
|
|
wolopts |= WAKE_PHY;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
|
|
if (ocp_data & UWF_EN)
|
|
wolopts |= WAKE_UCAST;
|
|
if (ocp_data & BWF_EN)
|
|
wolopts |= WAKE_BCAST;
|
|
if (ocp_data & MWF_EN)
|
|
wolopts |= WAKE_MCAST;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
|
|
if (ocp_data & MAGIC_EN)
|
|
wolopts |= WAKE_MAGIC;
|
|
|
|
return wolopts;
|
|
}
|
|
|
|
static void r8152_aldps_en(struct usbh_rtl8152 *tp, bool enable)
|
|
{
|
|
if (enable) {
|
|
ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | LINKENA | DIS_SDSAVE);
|
|
} else {
|
|
ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
|
|
usb_osal_msleep(20);
|
|
}
|
|
}
|
|
|
|
static void r8152_power_cut_en(struct usbh_rtl8152 *tp, bool enable)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
|
|
if (enable)
|
|
ocp_data |= POWER_CUT;
|
|
else
|
|
ocp_data &= ~POWER_CUT;
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
|
|
ocp_data &= ~RESUME_INDICATE;
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
|
|
}
|
|
|
|
static void rtl_tally_reset(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
|
|
ocp_data |= TALLY_RESET;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
|
|
}
|
|
|
|
static void r8152b_reset_packet_filter(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
|
|
ocp_data &= ~FMC_FCR_MCU_EN;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
|
|
ocp_data |= FMC_FCR_MCU_EN;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
|
|
}
|
|
|
|
static inline void r8153b_rx_agg_chg_indicate(struct usbh_rtl8152 *tp)
|
|
{
|
|
ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
|
|
OWN_UPDATE | OWN_CLEAR);
|
|
}
|
|
|
|
static void rxdy_gated_en(struct usbh_rtl8152 *tp, bool enable)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
|
|
if (enable)
|
|
ocp_data |= RXDY_GATED_EN;
|
|
else
|
|
ocp_data &= ~RXDY_GATED_EN;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
|
|
}
|
|
|
|
static inline uint16_t rtl8152_get_speed(struct usbh_rtl8152 *tp)
|
|
{
|
|
return ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
|
|
}
|
|
|
|
static void rtl_eee_plus_en(struct usbh_rtl8152 *tp, bool enable)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
|
|
if (enable)
|
|
ocp_data |= EEEP_CR_EEEP_TX;
|
|
else
|
|
ocp_data &= ~EEEP_CR_EEEP_TX;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
|
|
}
|
|
|
|
static void rtl_set_eee_plus(struct usbh_rtl8152 *tp)
|
|
{
|
|
if (rtl8152_get_speed(tp) & _10bps)
|
|
rtl_eee_plus_en(tp, true);
|
|
else
|
|
rtl_eee_plus_en(tp, false);
|
|
}
|
|
|
|
static void rtl8152_nic_reset(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
int i;
|
|
|
|
switch (tp->version) {
|
|
case RTL_TEST_01:
|
|
case RTL_VER_10:
|
|
case RTL_VER_11:
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
|
|
ocp_data &= ~CR_TE;
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
|
|
ocp_data &= ~BMU_RESET_EP_IN;
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
|
|
ocp_data |= CDC_ECM_EN;
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
|
|
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
|
|
ocp_data &= ~CR_RE;
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
|
|
ocp_data |= BMU_RESET_EP_IN;
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
|
|
ocp_data &= ~CDC_ECM_EN;
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
|
|
break;
|
|
|
|
default:
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
|
|
break;
|
|
usb_osal_msleep(400);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void rtl_disable(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
int i;
|
|
|
|
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
|
|
ocp_data &= ~RCR_ACPT_ALL;
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
|
|
|
|
rxdy_gated_en(tp, true);
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
|
|
if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
|
|
break;
|
|
usb_osal_msleep(1);
|
|
}
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
|
|
break;
|
|
usb_osal_msleep(1);
|
|
}
|
|
|
|
rtl8152_nic_reset(tp);
|
|
}
|
|
|
|
static void rtl_rx_vlan_en(struct usbh_rtl8152 *tp, bool enable)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
switch (tp->version) {
|
|
case RTL_VER_01:
|
|
case RTL_VER_02:
|
|
case RTL_VER_03:
|
|
case RTL_VER_04:
|
|
case RTL_VER_05:
|
|
case RTL_VER_06:
|
|
case RTL_VER_07:
|
|
case RTL_VER_08:
|
|
case RTL_VER_09:
|
|
case RTL_VER_14:
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
|
|
if (enable)
|
|
ocp_data |= CPCR_RX_VLAN;
|
|
else
|
|
ocp_data &= ~CPCR_RX_VLAN;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
|
|
break;
|
|
|
|
case RTL_TEST_01:
|
|
case RTL_VER_10:
|
|
case RTL_VER_11:
|
|
case RTL_VER_12:
|
|
case RTL_VER_13:
|
|
case RTL_VER_15:
|
|
default:
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RCR1);
|
|
if (enable)
|
|
ocp_data |= OUTER_VLAN | INNER_VLAN;
|
|
else
|
|
ocp_data &= ~(OUTER_VLAN | INNER_VLAN);
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RCR1, ocp_data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void wait_oob_link_list_ready(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
int i;
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
|
|
if (ocp_data & LINK_LIST_READY)
|
|
break;
|
|
usb_osal_msleep(1);
|
|
}
|
|
}
|
|
|
|
static void r8153_teredo_off(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
switch (tp->version) {
|
|
case RTL_VER_01:
|
|
case RTL_VER_02:
|
|
case RTL_VER_03:
|
|
case RTL_VER_04:
|
|
case RTL_VER_05:
|
|
case RTL_VER_06:
|
|
case RTL_VER_07:
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
|
|
ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK |
|
|
OOB_TEREDO_EN);
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
|
|
break;
|
|
|
|
case RTL_VER_08:
|
|
case RTL_VER_09:
|
|
case RTL_TEST_01:
|
|
case RTL_VER_10:
|
|
case RTL_VER_11:
|
|
case RTL_VER_12:
|
|
case RTL_VER_13:
|
|
case RTL_VER_14:
|
|
case RTL_VER_15:
|
|
default:
|
|
/* The bit 0 ~ 7 are relative with teredo settings. They are
|
|
* W1C (write 1 to clear), so set all 1 to disable it.
|
|
*/
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff);
|
|
break;
|
|
}
|
|
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
|
|
}
|
|
|
|
static void r8152b_exit_oob(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
|
|
ocp_data &= ~RCR_ACPT_ALL;
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
|
|
|
|
rxdy_gated_en(tp, true);
|
|
r8153_teredo_off(tp);
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
|
|
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
|
|
ocp_data &= ~NOW_IS_OOB;
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
|
|
ocp_data &= ~MCU_BORW_EN;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
|
|
|
|
wait_oob_link_list_ready(tp);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
|
|
ocp_data |= RE_INIT_LL;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
|
|
|
|
wait_oob_link_list_ready(tp);
|
|
|
|
rtl8152_nic_reset(tp);
|
|
|
|
/* rx share fifo credit full threshold */
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
|
|
|
|
if (tp->hport->speed == USB_SPEED_FULL ||
|
|
tp->hport->speed == USB_SPEED_LOW) {
|
|
/* rx share fifo credit near full threshold */
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
|
|
RXFIFO_THR2_FULL);
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
|
|
RXFIFO_THR3_FULL);
|
|
} else {
|
|
/* rx share fifo credit near full threshold */
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
|
|
RXFIFO_THR2_HIGH);
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
|
|
RXFIFO_THR3_HIGH);
|
|
}
|
|
|
|
/* TX share fifo free credit full threshold */
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
|
|
|
|
ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
|
|
ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
|
|
ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
|
|
TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
|
|
|
|
rtl_rx_vlan_en(tp, true);
|
|
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
|
|
ocp_data |= TCR0_AUTO_FIFO;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
|
|
}
|
|
|
|
static void r8152b_enter_oob(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
|
|
ocp_data &= ~NOW_IS_OOB;
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
|
|
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
|
|
|
|
rtl_disable(tp);
|
|
|
|
wait_oob_link_list_ready(tp);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
|
|
ocp_data |= RE_INIT_LL;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
|
|
|
|
wait_oob_link_list_ready(tp);
|
|
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
|
|
|
|
rtl_rx_vlan_en(tp, true);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
|
|
ocp_data |= ALDPS_PROXY_MODE;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
|
|
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
|
|
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
|
|
|
|
rxdy_gated_en(tp, false);
|
|
|
|
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
|
|
ocp_data |= RCR_APM | RCR_AM | RCR_AB;
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
|
|
}
|
|
|
|
static void r8152b_init(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
uint16_t data;
|
|
|
|
data = r8152_mdio_read(tp, MII_BMCR);
|
|
if (data & BMCR_PDOWN) {
|
|
data &= ~BMCR_PDOWN;
|
|
r8152_mdio_write(tp, MII_BMCR, data);
|
|
}
|
|
|
|
r8152_aldps_en(tp, false);
|
|
|
|
if (tp->version == RTL_VER_01) {
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
|
|
ocp_data &= ~LED_MODE_MASK;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
|
|
}
|
|
|
|
r8152_power_cut_en(tp, false);
|
|
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
|
|
ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
|
|
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
|
|
ocp_data &= ~MCU_CLK_RATIO_MASK;
|
|
ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
|
|
ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
|
|
SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
|
|
ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
|
|
|
|
rtl_tally_reset(tp);
|
|
|
|
/* enable rx aggregation */
|
|
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
|
|
ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
|
|
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
|
|
}
|
|
|
|
static int rtl_enable(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
|
|
r8152b_reset_packet_filter(tp);
|
|
|
|
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
|
|
ocp_data |= CR_RE | CR_TE;
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
|
|
|
|
switch (tp->version) {
|
|
case RTL_VER_01:
|
|
case RTL_VER_02:
|
|
case RTL_VER_03:
|
|
case RTL_VER_04:
|
|
case RTL_VER_05:
|
|
case RTL_VER_06:
|
|
case RTL_VER_07:
|
|
break;
|
|
default:
|
|
r8153b_rx_agg_chg_indicate(tp);
|
|
break;
|
|
}
|
|
|
|
rxdy_gated_en(tp, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rtl8152_enable(struct usbh_rtl8152 *tp)
|
|
{
|
|
rtl_set_eee_plus(tp);
|
|
|
|
return rtl_enable(tp);
|
|
}
|
|
|
|
static void rtl8152_disable(struct usbh_rtl8152 *tp)
|
|
{
|
|
r8152_aldps_en(tp, false);
|
|
rtl_disable(tp);
|
|
r8152_aldps_en(tp, true);
|
|
}
|
|
|
|
static void rtl8152_up(struct usbh_rtl8152 *tp)
|
|
{
|
|
r8152_aldps_en(tp, false);
|
|
r8152b_exit_oob(tp);
|
|
r8152_aldps_en(tp, true);
|
|
}
|
|
|
|
static void rtl8152_down(struct usbh_rtl8152 *tp)
|
|
{
|
|
r8152_power_cut_en(tp, false);
|
|
r8152_aldps_en(tp, false);
|
|
r8152b_enter_oob(tp);
|
|
r8152_aldps_en(tp, true);
|
|
}
|
|
|
|
static int rtl_ops_init(struct usbh_rtl8152 *tp)
|
|
{
|
|
struct rtl_ops *ops = &tp->rtl_ops;
|
|
int ret = 0;
|
|
|
|
switch (tp->version) {
|
|
case RTL_VER_01:
|
|
case RTL_VER_02:
|
|
case RTL_VER_07:
|
|
ops->init = r8152b_init;
|
|
ops->enable = rtl8152_enable;
|
|
ops->disable = rtl8152_disable;
|
|
ops->up = rtl8152_up;
|
|
ops->down = rtl8152_down;
|
|
// ops->unload = rtl8152_unload;
|
|
// ops->eee_get = r8152_get_eee;
|
|
// ops->eee_set = r8152_set_eee;
|
|
// ops->in_nway = rtl8152_in_nway;
|
|
// ops->hw_phy_cfg = r8152b_hw_phy_cfg;
|
|
// ops->autosuspend_en = rtl_runtime_suspend_enable;
|
|
tp->rx_buf_sz = 16 * 1024;
|
|
tp->eee_en = true;
|
|
//tp->eee_adv = MDIO_EEE_100TX;
|
|
break;
|
|
|
|
// case RTL_VER_03:
|
|
// case RTL_VER_04:
|
|
// case RTL_VER_05:
|
|
// case RTL_VER_06:
|
|
// break;
|
|
|
|
// case RTL_VER_08:
|
|
// case RTL_VER_09:
|
|
// break;
|
|
|
|
// case RTL_VER_11:
|
|
// case RTL_VER_10:
|
|
// break;
|
|
|
|
// case RTL_VER_12:
|
|
// case RTL_VER_13:
|
|
// case RTL_VER_15:
|
|
// break;
|
|
|
|
// case RTL_VER_14:
|
|
// break;
|
|
|
|
default:
|
|
ret = -USB_ERR_NODEV;
|
|
USB_LOG_ERR("Unsupport rtl version:%d\r\n", tp->version);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void rtl8152_set_rx_mode(struct usbh_rtl8152 *tp)
|
|
{
|
|
uint32_t ocp_data;
|
|
uint32_t mc_filter[2];
|
|
|
|
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
|
|
ocp_data &= ~RCR_ACPT_ALL;
|
|
ocp_data |= RCR_AB | RCR_APM;
|
|
|
|
ocp_data |= RCR_AM;
|
|
mc_filter[1] = 0xffffffff;
|
|
mc_filter[0] = 0xffffffff;
|
|
|
|
pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(mc_filter), mc_filter);
|
|
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
|
|
}
|
|
|
|
static int rtl8152_set_speed(struct usbh_rtl8152 *tp, uint8_t autoneg, uint16_t speed, uint8_t duplex)
|
|
{
|
|
uint16_t bmcr, anar, gbcr;
|
|
|
|
anar = r8152_mdio_read(tp, MII_ADVERTISE);
|
|
anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
|
|
ADVERTISE_100HALF | ADVERTISE_100FULL);
|
|
if (tp->supports_gmii) {
|
|
gbcr = r8152_mdio_read(tp, MII_CTRL1000);
|
|
gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
|
} else {
|
|
gbcr = 0;
|
|
}
|
|
|
|
if (autoneg == AUTONEG_DISABLE) {
|
|
if (speed == SPEED_10) {
|
|
bmcr = 0;
|
|
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
|
|
} else if (speed == SPEED_100) {
|
|
bmcr = BMCR_SPEED100;
|
|
anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
|
|
} else if (speed == SPEED_1000 && tp->supports_gmii) {
|
|
bmcr = BMCR_SPEED1000;
|
|
gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
|
} else {
|
|
return -USB_ERR_INVAL;
|
|
}
|
|
|
|
if (duplex == DUPLEX_FULL)
|
|
bmcr |= BMCR_FULLDPLX;
|
|
} else {
|
|
if (speed == SPEED_10) {
|
|
if (duplex == DUPLEX_FULL)
|
|
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
|
|
else
|
|
anar |= ADVERTISE_10HALF;
|
|
} else if (speed == SPEED_100) {
|
|
if (duplex == DUPLEX_FULL) {
|
|
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
|
|
anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
|
|
} else {
|
|
anar |= ADVERTISE_10HALF;
|
|
anar |= ADVERTISE_100HALF;
|
|
}
|
|
} else if (speed == SPEED_1000 && tp->supports_gmii) {
|
|
if (duplex == DUPLEX_FULL) {
|
|
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
|
|
anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
|
|
gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
|
|
} else {
|
|
anar |= ADVERTISE_10HALF;
|
|
anar |= ADVERTISE_100HALF;
|
|
gbcr |= ADVERTISE_1000HALF;
|
|
}
|
|
} else {
|
|
return -USB_ERR_INVAL;
|
|
}
|
|
|
|
bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
|
|
}
|
|
|
|
if (tp->supports_gmii)
|
|
r8152_mdio_write(tp, MII_CTRL1000, gbcr);
|
|
|
|
r8152_mdio_write(tp, MII_ADVERTISE, anar);
|
|
r8152_mdio_write(tp, MII_BMCR, bmcr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int r8152_write_hwaddr(struct usbh_rtl8152 *tp, unsigned char *mac)
|
|
{
|
|
unsigned char enetaddr[8] = { 0 };
|
|
memcpy(enetaddr, mac, 6);
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
|
|
pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, enetaddr);
|
|
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
|
|
return 0;
|
|
}
|
|
|
|
int usbh_rtl8152_get_connect_status(struct usbh_rtl8152 *rtl8152_class)
|
|
{
|
|
int ret;
|
|
|
|
usbh_int_urb_fill(&rtl8152_class->intin_urb, rtl8152_class->hport, rtl8152_class->intin, g_rtl8152_inttx_buffer, 2, USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
|
ret = usbh_submit_urb(&rtl8152_class->intin_urb);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (g_rtl8152_inttx_buffer[0] & INTR_LINK) {
|
|
rtl8152_class->connect_status = true;
|
|
} else {
|
|
rtl8152_class->connect_status = false;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int usbh_rtl8152_connect(struct usbh_hubport *hport, uint8_t intf)
|
|
{
|
|
struct usb_endpoint_descriptor *ep_desc;
|
|
char mac_buffer[12];
|
|
int ret;
|
|
|
|
struct usbh_rtl8152 *rtl8152_class = &g_rtl8152_class;
|
|
|
|
memset(rtl8152_class, 0, sizeof(struct usbh_rtl8152));
|
|
|
|
rtl8152_class->hport = hport;
|
|
rtl8152_class->intf = intf;
|
|
|
|
hport->config.intf[intf].priv = rtl8152_class;
|
|
|
|
rtl8152_class->version = usbh_rtl8152_get_version(rtl8152_class);
|
|
|
|
if (rtl8152_class->version == RTL_VER_UNKNOWN) {
|
|
USB_LOG_ERR("Unknown version 0x%04x\r\n", rtl8152_class->version);
|
|
return -USB_ERR_NOTSUPP;
|
|
} else {
|
|
USB_LOG_INFO("rtl8152 version 0x%04x\r\n", rtl8152_class->version);
|
|
}
|
|
|
|
/* MTU range: 68 - 1500 or 9194 */
|
|
rtl8152_class->min_mtu = 68;
|
|
switch (rtl8152_class->version) {
|
|
case RTL_VER_03:
|
|
case RTL_VER_04:
|
|
case RTL_VER_05:
|
|
case RTL_VER_06:
|
|
case RTL_VER_08:
|
|
case RTL_VER_09:
|
|
case RTL_VER_14:
|
|
rtl8152_class->max_mtu = size_to_mtu(9 * 1024);
|
|
break;
|
|
case RTL_VER_10:
|
|
case RTL_VER_11:
|
|
rtl8152_class->max_mtu = size_to_mtu(15 * 1024);
|
|
break;
|
|
case RTL_VER_12:
|
|
case RTL_VER_13:
|
|
case RTL_VER_15:
|
|
rtl8152_class->max_mtu = size_to_mtu(16 * 1024);
|
|
break;
|
|
case RTL_VER_01:
|
|
case RTL_VER_02:
|
|
case RTL_VER_07:
|
|
default:
|
|
rtl8152_class->max_mtu = 1500;
|
|
break;
|
|
}
|
|
|
|
rtl8152_class->saved_wolopts = __rtl_get_wol(rtl8152_class);
|
|
if (rtl_ops_init(rtl8152_class) < 0) {
|
|
return -USB_ERR_NODEV;
|
|
}
|
|
|
|
rtl8152_class->rtl_ops.init(rtl8152_class);
|
|
rtl8152_class->rtl_ops.up(rtl8152_class);
|
|
|
|
if (rtl8152_class->rx_buf_sz > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
|
|
USB_LOG_ERR("rx_buf_sz is overflow, default is %d\r\n", CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE);
|
|
return -USB_ERR_NOMEM;
|
|
}
|
|
|
|
memset(mac_buffer, 0, 12);
|
|
ret = usbh_get_string_desc(rtl8152_class->hport, 3, (uint8_t *)mac_buffer);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
for (int i = 0, j = 0; i < 12; i += 2, j++) {
|
|
char byte_str[3];
|
|
byte_str[0] = mac_buffer[i];
|
|
byte_str[1] = mac_buffer[i + 1];
|
|
byte_str[2] = '\0';
|
|
|
|
uint32_t byte = strtoul(byte_str, NULL, 16);
|
|
rtl8152_class->mac[j] = (unsigned char)byte;
|
|
}
|
|
|
|
r8152_write_hwaddr(rtl8152_class, rtl8152_class->mac);
|
|
|
|
USB_LOG_INFO("RTL8152 MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
|
|
rtl8152_class->mac[0],
|
|
rtl8152_class->mac[1],
|
|
rtl8152_class->mac[2],
|
|
rtl8152_class->mac[3],
|
|
rtl8152_class->mac[4],
|
|
rtl8152_class->mac[5]);
|
|
|
|
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
|
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
|
|
|
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
|
|
if (ep_desc->bEndpointAddress & 0x80) {
|
|
USBH_EP_INIT(rtl8152_class->intin, ep_desc);
|
|
} else {
|
|
return -USB_ERR_NOTSUPP;
|
|
}
|
|
} else {
|
|
if (ep_desc->bEndpointAddress & 0x80) {
|
|
USBH_EP_INIT(rtl8152_class->bulkin, ep_desc);
|
|
} else {
|
|
USBH_EP_INIT(rtl8152_class->bulkout, ep_desc);
|
|
}
|
|
}
|
|
}
|
|
|
|
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
|
|
|
|
USB_LOG_INFO("Register RTL8152 Class:%s\r\n", hport->config.intf[intf].devname);
|
|
|
|
usbh_rtl8152_run(rtl8152_class);
|
|
return 0;
|
|
}
|
|
|
|
static int usbh_rtl8152_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
|
{
|
|
int ret = 0;
|
|
|
|
struct usbh_rtl8152 *rtl8152_class = (struct usbh_rtl8152 *)hport->config.intf[intf].priv;
|
|
|
|
if (rtl8152_class) {
|
|
if (rtl8152_class->bulkin) {
|
|
usbh_kill_urb(&rtl8152_class->bulkin_urb);
|
|
}
|
|
|
|
if (rtl8152_class->bulkout) {
|
|
usbh_kill_urb(&rtl8152_class->bulkout_urb);
|
|
}
|
|
|
|
if (rtl8152_class->intin) {
|
|
usbh_kill_urb(&rtl8152_class->intin_urb);
|
|
}
|
|
|
|
if (hport->config.intf[intf].devname[0] != '\0') {
|
|
USB_LOG_INFO("Unregister rtl8152 Class:%s\r\n", hport->config.intf[intf].devname);
|
|
usbh_rtl8152_stop(rtl8152_class);
|
|
}
|
|
|
|
memset(rtl8152_class, 0, sizeof(struct usbh_rtl8152));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void usbh_rtl8152_rx_thread(void *argument)
|
|
{
|
|
uint32_t g_rtl8152_rx_length;
|
|
int ret;
|
|
uint16_t len;
|
|
uint16_t data_offset;
|
|
#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE <= (16 * 1024)
|
|
uint32_t transfer_size = CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE;
|
|
#else
|
|
uint32_t transfer_size = (16 * 1024);
|
|
#endif
|
|
|
|
(void)argument;
|
|
USB_LOG_INFO("Create rtl8152 rx thread\r\n");
|
|
// clang-format off
|
|
find_class:
|
|
// clang-format on
|
|
g_rtl8152_class.connect_status = false;
|
|
if (usbh_find_class_instance("/dev/rtl8152") == NULL) {
|
|
goto delete;
|
|
}
|
|
|
|
while (g_rtl8152_class.connect_status == false) {
|
|
ret = usbh_rtl8152_get_connect_status(&g_rtl8152_class);
|
|
if (ret < 0) {
|
|
usb_osal_msleep(100);
|
|
goto find_class;
|
|
}
|
|
usb_osal_msleep(128);
|
|
}
|
|
|
|
if (g_rtl8152_class.rtl_ops.enable) {
|
|
g_rtl8152_class.rtl_ops.enable(&g_rtl8152_class);
|
|
} else {
|
|
goto delete;
|
|
}
|
|
|
|
rtl8152_set_rx_mode(&g_rtl8152_class);
|
|
rtl8152_set_speed(&g_rtl8152_class, AUTONEG_ENABLE, g_rtl8152_class.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL);
|
|
|
|
g_rtl8152_rx_length = 0;
|
|
while (1) {
|
|
usbh_bulk_urb_fill(&g_rtl8152_class.bulkin_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkin, &g_rtl8152_rx_buffer[g_rtl8152_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
|
ret = usbh_submit_urb(&g_rtl8152_class.bulkin_urb);
|
|
if (ret < 0) {
|
|
goto find_class;
|
|
}
|
|
|
|
g_rtl8152_rx_length += g_rtl8152_class.bulkin_urb.actual_length;
|
|
|
|
/* A transfer is complete because last packet is a short packet.
|
|
* Short packet is not zero, match g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize).
|
|
* Short packet is zero, check if g_rtl8152_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
|
|
*/
|
|
if (g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize) ||
|
|
(g_rtl8152_class.bulkin_urb.actual_length < transfer_size)) {
|
|
data_offset = 0;
|
|
|
|
USB_LOG_DBG("rxlen:%d\r\n", g_rtl8152_rx_length);
|
|
while (g_rtl8152_rx_length > 0) {
|
|
struct rx_desc *rx_desc = (struct rx_desc *)&g_rtl8152_rx_buffer[data_offset];
|
|
|
|
len = rx_desc->opts1 & RX_LEN_MASK;
|
|
|
|
USB_LOG_DBG("data_offset:%d, eth len:%d\r\n", data_offset, len);
|
|
|
|
uint8_t *buf = (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)];
|
|
usbh_rtl8152_eth_input(buf, len);
|
|
|
|
data_offset += (len + sizeof(struct rx_desc));
|
|
g_rtl8152_rx_length -= (len + sizeof(struct rx_desc));
|
|
|
|
if (len & (RX_ALIGN - 1)) {
|
|
data_offset += (RX_ALIGN - (len & (RX_ALIGN - 1)));
|
|
g_rtl8152_rx_length -= (RX_ALIGN - (len & (RX_ALIGN - 1)));
|
|
}
|
|
}
|
|
} else {
|
|
#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE <= (16 * 1024)
|
|
if (g_rtl8152_rx_length == CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
|
|
#else
|
|
if ((g_rtl8152_rx_length + (16 * 1024)) > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
|
|
#endif
|
|
USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE\r\n");
|
|
while (1) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// clang-format off
|
|
delete:
|
|
USB_LOG_INFO("Delete rtl8152 rx thread\r\n");
|
|
usb_osal_thread_delete(NULL);
|
|
// clang-format on
|
|
}
|
|
|
|
uint8_t *usbh_rtl8152_get_eth_txbuf(void)
|
|
{
|
|
return (g_rtl8152_tx_buffer + sizeof(struct tx_desc));
|
|
}
|
|
|
|
int usbh_rtl8152_eth_output(uint32_t buflen)
|
|
{
|
|
struct tx_desc *tx_desc;
|
|
|
|
if (g_rtl8152_class.connect_status == false) {
|
|
return -USB_ERR_NOTCONN;
|
|
}
|
|
|
|
tx_desc = (struct tx_desc *)g_rtl8152_tx_buffer;
|
|
tx_desc->opts1 = buflen | TX_FS | TX_LS;
|
|
tx_desc->opts2 = 0;
|
|
|
|
USB_LOG_DBG("txlen:%d\r\n", buflen + sizeof(struct tx_desc));
|
|
|
|
usbh_bulk_urb_fill(&g_rtl8152_class.bulkout_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkout, g_rtl8152_tx_buffer, buflen + sizeof(struct tx_desc), USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
|
return usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
|
|
}
|
|
|
|
__WEAK void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
|
|
{
|
|
(void)rtl8152_class;
|
|
}
|
|
|
|
__WEAK void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
|
|
{
|
|
(void)rtl8152_class;
|
|
}
|
|
|
|
static const uint16_t rtl_id_table[][2] = {
|
|
{ 0x0BDA, 0x8152 },
|
|
{ 0, 0 },
|
|
};
|
|
|
|
static const struct usbh_class_driver rtl8152_class_driver = {
|
|
.driver_name = "rtl8152",
|
|
.connect = usbh_rtl8152_connect,
|
|
.disconnect = usbh_rtl8152_disconnect
|
|
};
|
|
|
|
CLASS_INFO_DEFINE const struct usbh_class_info rtl8152_class_info = {
|
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
|
.bInterfaceClass = 0xff,
|
|
.bInterfaceSubClass = 0x00,
|
|
.bInterfaceProtocol = 0x00,
|
|
.id_table = rtl_id_table,
|
|
.class_driver = &rtl8152_class_driver
|
|
};
|