1ba4dfef1SStephen Warren /* 2ba4dfef1SStephen Warren * Copyright (c) 2016, NVIDIA CORPORATION. 3ba4dfef1SStephen Warren * 4ba4dfef1SStephen Warren * SPDX-License-Identifier: GPL-2.0 5ba4dfef1SStephen Warren * 6ba4dfef1SStephen Warren * Portions based on U-Boot's rtl8169.c. 7ba4dfef1SStephen Warren */ 8ba4dfef1SStephen Warren 9ba4dfef1SStephen Warren /* 10ba4dfef1SStephen Warren * This driver supports the Synopsys Designware Ethernet QOS (Quality Of 11ba4dfef1SStephen Warren * Service) IP block. The IP supports multiple options for bus type, clocking/ 12ba4dfef1SStephen Warren * reset structure, and feature list. 13ba4dfef1SStephen Warren * 14ba4dfef1SStephen Warren * The driver is written such that generic core logic is kept separate from 15ba4dfef1SStephen Warren * configuration-specific logic. Code that interacts with configuration- 16ba4dfef1SStephen Warren * specific resources is split out into separate functions to avoid polluting 17ba4dfef1SStephen Warren * common code. If/when this driver is enhanced to support multiple 18ba4dfef1SStephen Warren * configurations, the core code should be adapted to call all configuration- 19ba4dfef1SStephen Warren * specific functions through function pointers, with the definition of those 20ba4dfef1SStephen Warren * function pointers being supplied by struct udevice_id eqos_ids[]'s .data 21ba4dfef1SStephen Warren * field. 22ba4dfef1SStephen Warren * 23ba4dfef1SStephen Warren * The following configurations are currently supported: 24ba4dfef1SStephen Warren * tegra186: 25ba4dfef1SStephen Warren * NVIDIA's Tegra186 chip. This configuration uses an AXI master/DMA bus, an 26ba4dfef1SStephen Warren * AHB slave/register bus, contains the DMA, MTL, and MAC sub-blocks, and 27ba4dfef1SStephen Warren * supports a single RGMII PHY. This configuration also has SW control over 28ba4dfef1SStephen Warren * all clock and reset signals to the HW block. 29ba4dfef1SStephen Warren */ 30ba4dfef1SStephen Warren #include <common.h> 31ba4dfef1SStephen Warren #include <clk.h> 32ba4dfef1SStephen Warren #include <dm.h> 33ba4dfef1SStephen Warren #include <errno.h> 34ba4dfef1SStephen Warren #include <memalign.h> 35ba4dfef1SStephen Warren #include <miiphy.h> 36ba4dfef1SStephen Warren #include <net.h> 37ba4dfef1SStephen Warren #include <netdev.h> 38ba4dfef1SStephen Warren #include <phy.h> 39ba4dfef1SStephen Warren #include <reset.h> 40ba4dfef1SStephen Warren #include <wait_bit.h> 41ba4dfef1SStephen Warren #include <asm/gpio.h> 42ba4dfef1SStephen Warren #include <asm/io.h> 438e3eceb0SYe Li #include <eth_phy.h> 44ad018a0cSFugang Duan #ifdef CONFIG_ARCH_IMX8M 45ad018a0cSFugang Duan #include <asm/arch/clock.h> 46ad018a0cSFugang Duan #include <asm/mach-imx/sys_proto.h> 47ad018a0cSFugang Duan #endif 4823ca6f74SDavid Wu #include "dwc_eth_qos.h" 49ba4dfef1SStephen Warren 50ba4dfef1SStephen Warren /* Core registers */ 51ba4dfef1SStephen Warren 52ba4dfef1SStephen Warren #define EQOS_MAC_REGS_BASE 0x000 53ba4dfef1SStephen Warren struct eqos_mac_regs { 54ba4dfef1SStephen Warren uint32_t configuration; /* 0x000 */ 55ba4dfef1SStephen Warren uint32_t unused_004[(0x070 - 0x004) / 4]; /* 0x004 */ 56ba4dfef1SStephen Warren uint32_t q0_tx_flow_ctrl; /* 0x070 */ 57ba4dfef1SStephen Warren uint32_t unused_070[(0x090 - 0x074) / 4]; /* 0x074 */ 58ba4dfef1SStephen Warren uint32_t rx_flow_ctrl; /* 0x090 */ 59ba4dfef1SStephen Warren uint32_t unused_094; /* 0x094 */ 60ba4dfef1SStephen Warren uint32_t txq_prty_map0; /* 0x098 */ 61ba4dfef1SStephen Warren uint32_t unused_09c; /* 0x09c */ 62ba4dfef1SStephen Warren uint32_t rxq_ctrl0; /* 0x0a0 */ 63ba4dfef1SStephen Warren uint32_t unused_0a4; /* 0x0a4 */ 64ba4dfef1SStephen Warren uint32_t rxq_ctrl2; /* 0x0a8 */ 65ba4dfef1SStephen Warren uint32_t unused_0ac[(0x0dc - 0x0ac) / 4]; /* 0x0ac */ 66ba4dfef1SStephen Warren uint32_t us_tic_counter; /* 0x0dc */ 67ba4dfef1SStephen Warren uint32_t unused_0e0[(0x11c - 0x0e0) / 4]; /* 0x0e0 */ 68ba4dfef1SStephen Warren uint32_t hw_feature0; /* 0x11c */ 69ba4dfef1SStephen Warren uint32_t hw_feature1; /* 0x120 */ 70ba4dfef1SStephen Warren uint32_t hw_feature2; /* 0x124 */ 71ba4dfef1SStephen Warren uint32_t unused_128[(0x200 - 0x128) / 4]; /* 0x128 */ 72ba4dfef1SStephen Warren uint32_t mdio_address; /* 0x200 */ 73ba4dfef1SStephen Warren uint32_t mdio_data; /* 0x204 */ 74ba4dfef1SStephen Warren uint32_t unused_208[(0x300 - 0x208) / 4]; /* 0x208 */ 75ba4dfef1SStephen Warren uint32_t address0_high; /* 0x300 */ 76ba4dfef1SStephen Warren uint32_t address0_low; /* 0x304 */ 77ba4dfef1SStephen Warren }; 78ba4dfef1SStephen Warren 79ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_GPSLCE BIT(23) 80ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_CST BIT(21) 81ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_ACS BIT(20) 82ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_WD BIT(19) 83ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_JD BIT(17) 84ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_JE BIT(16) 85ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_PS BIT(15) 86ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_FES BIT(14) 87ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_DM BIT(13) 88a7b3400fSFugang Duan #define EQOS_MAC_CONFIGURATION_LM BIT(12) 89ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_TE BIT(1) 90ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_RE BIT(0) 91ba4dfef1SStephen Warren 92ba4dfef1SStephen Warren #define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT 16 93ba4dfef1SStephen Warren #define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_MASK 0xffff 94ba4dfef1SStephen Warren #define EQOS_MAC_Q0_TX_FLOW_CTRL_TFE BIT(1) 95ba4dfef1SStephen Warren 96ba4dfef1SStephen Warren #define EQOS_MAC_RX_FLOW_CTRL_RFE BIT(0) 97ba4dfef1SStephen Warren 98ba4dfef1SStephen Warren #define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_SHIFT 0 99ba4dfef1SStephen Warren #define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK 0xff 100ba4dfef1SStephen Warren 101ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT 0 102ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 103ba4dfef1SStephen Warren 104ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 105ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff 106ba4dfef1SStephen Warren 107a7b3400fSFugang Duan #define EQOS_MAC_HW_FEATURE0_MMCSEL_SHIFT 8 108a7b3400fSFugang Duan #define EQOS_MAC_HW_FEATURE0_HDSEL_SHIFT 2 109a7b3400fSFugang Duan #define EQOS_MAC_HW_FEATURE0_GMIISEL_SHIFT 1 110a7b3400fSFugang Duan #define EQOS_MAC_HW_FEATURE0_MIISEL_SHIFT 0 111a7b3400fSFugang Duan 112ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT 6 113ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK 0x1f 114ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT 0 115ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK 0x1f 116ba4dfef1SStephen Warren 117a7b3400fSFugang Duan #define EQOS_MAC_HW_FEATURE3_ASP_SHIFT 28 118a7b3400fSFugang Duan #define EQOS_MAC_HW_FEATURE3_ASP_MASK 0x3 119a7b3400fSFugang Duan 120ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21 121ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 122ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 123ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) 124ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 125ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 126ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GOC_WRITE 1 127ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_C45E BIT(1) 128ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GB BIT(0) 129ba4dfef1SStephen Warren 130ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_DATA_GD_MASK 0xffff 131ba4dfef1SStephen Warren 132ba4dfef1SStephen Warren #define EQOS_MTL_REGS_BASE 0xd00 133ba4dfef1SStephen Warren struct eqos_mtl_regs { 134ba4dfef1SStephen Warren uint32_t txq0_operation_mode; /* 0xd00 */ 135ba4dfef1SStephen Warren uint32_t unused_d04; /* 0xd04 */ 136ba4dfef1SStephen Warren uint32_t txq0_debug; /* 0xd08 */ 137ba4dfef1SStephen Warren uint32_t unused_d0c[(0xd18 - 0xd0c) / 4]; /* 0xd0c */ 138ba4dfef1SStephen Warren uint32_t txq0_quantum_weight; /* 0xd18 */ 139ba4dfef1SStephen Warren uint32_t unused_d1c[(0xd30 - 0xd1c) / 4]; /* 0xd1c */ 140ba4dfef1SStephen Warren uint32_t rxq0_operation_mode; /* 0xd30 */ 141ba4dfef1SStephen Warren uint32_t unused_d34; /* 0xd34 */ 142ba4dfef1SStephen Warren uint32_t rxq0_debug; /* 0xd38 */ 143ba4dfef1SStephen Warren }; 144ba4dfef1SStephen Warren 145ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT 16 146ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_MASK 0x1ff 147ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT 2 148ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_MASK 3 149ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED 2 150ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TSF BIT(1) 151ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_FTQ BIT(0) 152ba4dfef1SStephen Warren 153ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_DEBUG_TXQSTS BIT(4) 154ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_DEBUG_TRCSTS_SHIFT 1 155ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_DEBUG_TRCSTS_MASK 3 156ba4dfef1SStephen Warren 157ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT 20 158ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_MASK 0x3ff 159ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT 14 160ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_MASK 0x3f 161ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT 8 162ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f 163ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7) 164ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5) 165a7b3400fSFugang Duan #define EQOS_MTL_RXQ0_OPERATION_MODE_FEP BIT(4) 166a7b3400fSFugang Duan #define EQOS_MTL_RXQ0_OPERATION_MODE_FUP BIT(3) 167ba4dfef1SStephen Warren 168ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16 169ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff 170ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_RXQSTS_SHIFT 4 171ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_RXQSTS_MASK 3 172ba4dfef1SStephen Warren 173ba4dfef1SStephen Warren #define EQOS_DMA_REGS_BASE 0x1000 174ba4dfef1SStephen Warren struct eqos_dma_regs { 175ba4dfef1SStephen Warren uint32_t mode; /* 0x1000 */ 176ba4dfef1SStephen Warren uint32_t sysbus_mode; /* 0x1004 */ 177ba4dfef1SStephen Warren uint32_t unused_1008[(0x1100 - 0x1008) / 4]; /* 0x1008 */ 178ba4dfef1SStephen Warren uint32_t ch0_control; /* 0x1100 */ 179ba4dfef1SStephen Warren uint32_t ch0_tx_control; /* 0x1104 */ 180ba4dfef1SStephen Warren uint32_t ch0_rx_control; /* 0x1108 */ 181ba4dfef1SStephen Warren uint32_t unused_110c; /* 0x110c */ 182ba4dfef1SStephen Warren uint32_t ch0_txdesc_list_haddress; /* 0x1110 */ 183ba4dfef1SStephen Warren uint32_t ch0_txdesc_list_address; /* 0x1114 */ 184ba4dfef1SStephen Warren uint32_t ch0_rxdesc_list_haddress; /* 0x1118 */ 185ba4dfef1SStephen Warren uint32_t ch0_rxdesc_list_address; /* 0x111c */ 186ba4dfef1SStephen Warren uint32_t ch0_txdesc_tail_pointer; /* 0x1120 */ 187ba4dfef1SStephen Warren uint32_t unused_1124; /* 0x1124 */ 188ba4dfef1SStephen Warren uint32_t ch0_rxdesc_tail_pointer; /* 0x1128 */ 189ba4dfef1SStephen Warren uint32_t ch0_txdesc_ring_length; /* 0x112c */ 190ba4dfef1SStephen Warren uint32_t ch0_rxdesc_ring_length; /* 0x1130 */ 191ba4dfef1SStephen Warren }; 192ba4dfef1SStephen Warren 193ba4dfef1SStephen Warren #define EQOS_DMA_MODE_SWR BIT(0) 194ba4dfef1SStephen Warren 195ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT 16 196ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK 0xf 197ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_EAME BIT(11) 198ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_BLEN16 BIT(3) 199ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_BLEN8 BIT(2) 200ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_BLEN4 BIT(1) 201ba4dfef1SStephen Warren 202ba4dfef1SStephen Warren #define EQOS_DMA_CH0_CONTROL_PBLX8 BIT(16) 203ba4dfef1SStephen Warren 204ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT 16 205ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_TXPBL_MASK 0x3f 206ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_OSP BIT(4) 207ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_ST BIT(0) 208ba4dfef1SStephen Warren 209ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT 16 210ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RXPBL_MASK 0x3f 211ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT 1 212ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RBSZ_MASK 0x3fff 213ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_SR BIT(0) 214ba4dfef1SStephen Warren 215ba4dfef1SStephen Warren /* These registers are Tegra186-specific */ 216ba4dfef1SStephen Warren #define EQOS_TEGRA186_REGS_BASE 0x8800 217ba4dfef1SStephen Warren struct eqos_tegra186_regs { 218ba4dfef1SStephen Warren uint32_t sdmemcomppadctrl; /* 0x8800 */ 219ba4dfef1SStephen Warren uint32_t auto_cal_config; /* 0x8804 */ 220ba4dfef1SStephen Warren uint32_t unused_8808; /* 0x8808 */ 221ba4dfef1SStephen Warren uint32_t auto_cal_status; /* 0x880c */ 222ba4dfef1SStephen Warren }; 223ba4dfef1SStephen Warren 224ba4dfef1SStephen Warren #define EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31) 225ba4dfef1SStephen Warren 226ba4dfef1SStephen Warren #define EQOS_AUTO_CAL_CONFIG_START BIT(31) 227ba4dfef1SStephen Warren #define EQOS_AUTO_CAL_CONFIG_ENABLE BIT(29) 228ba4dfef1SStephen Warren 229ba4dfef1SStephen Warren #define EQOS_AUTO_CAL_STATUS_ACTIVE BIT(31) 230ba4dfef1SStephen Warren 231ba4dfef1SStephen Warren /* Descriptors */ 232ba4dfef1SStephen Warren 233ba4dfef1SStephen Warren #define EQOS_DESCRIPTOR_WORDS 4 234ba4dfef1SStephen Warren #define EQOS_DESCRIPTOR_SIZE (EQOS_DESCRIPTOR_WORDS * 4) 235ba4dfef1SStephen Warren /* We assume ARCH_DMA_MINALIGN >= 16; 16 is the EQOS HW minimum */ 236ba4dfef1SStephen Warren #define EQOS_DESCRIPTOR_ALIGN ARCH_DMA_MINALIGN 237ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_TX 4 238ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_RX 4 239ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX) 240ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_SIZE ALIGN(EQOS_DESCRIPTORS_NUM * \ 241ba4dfef1SStephen Warren EQOS_DESCRIPTOR_SIZE, ARCH_DMA_MINALIGN) 242ba4dfef1SStephen Warren #define EQOS_BUFFER_ALIGN ARCH_DMA_MINALIGN 243ba4dfef1SStephen Warren #define EQOS_MAX_PACKET_SIZE ALIGN(1568, ARCH_DMA_MINALIGN) 244ba4dfef1SStephen Warren #define EQOS_RX_BUFFER_SIZE (EQOS_DESCRIPTORS_RX * EQOS_MAX_PACKET_SIZE) 245ba4dfef1SStephen Warren 246ba4dfef1SStephen Warren /* 247ba4dfef1SStephen Warren * Warn if the cache-line size is larger than the descriptor size. In such 248ba4dfef1SStephen Warren * cases the driver will likely fail because the CPU needs to flush the cache 249ba4dfef1SStephen Warren * when requeuing RX buffers, therefore descriptors written by the hardware 250ba4dfef1SStephen Warren * may be discarded. Architectures with full IO coherence, such as x86, do not 251ba4dfef1SStephen Warren * experience this issue, and hence are excluded from this condition. 252ba4dfef1SStephen Warren * 253ba4dfef1SStephen Warren * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause 254ba4dfef1SStephen Warren * the driver to allocate descriptors from a pool of non-cached memory. 255ba4dfef1SStephen Warren */ 256ba4dfef1SStephen Warren #if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN 257ba4dfef1SStephen Warren #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ 258ba4dfef1SStephen Warren !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) 259ba4dfef1SStephen Warren #warning Cache line size is larger than descriptor size 260ba4dfef1SStephen Warren #endif 261ba4dfef1SStephen Warren #endif 262ba4dfef1SStephen Warren 263ba4dfef1SStephen Warren struct eqos_desc { 264ba4dfef1SStephen Warren u32 des0; 265ba4dfef1SStephen Warren u32 des1; 266ba4dfef1SStephen Warren u32 des2; 267ba4dfef1SStephen Warren u32 des3; 268ba4dfef1SStephen Warren }; 269ba4dfef1SStephen Warren 270ba4dfef1SStephen Warren #define EQOS_DESC3_OWN BIT(31) 271ba4dfef1SStephen Warren #define EQOS_DESC3_FD BIT(29) 272ba4dfef1SStephen Warren #define EQOS_DESC3_LD BIT(28) 273ba4dfef1SStephen Warren #define EQOS_DESC3_BUF1V BIT(24) 274ba4dfef1SStephen Warren 275ba4dfef1SStephen Warren /* 276ba4dfef1SStephen Warren * TX and RX descriptors are 16 bytes. This causes problems with the cache 277ba4dfef1SStephen Warren * maintenance on CPUs where the cache-line size exceeds the size of these 278ba4dfef1SStephen Warren * descriptors. What will happen is that when the driver receives a packet 279ba4dfef1SStephen Warren * it will be immediately requeued for the hardware to reuse. The CPU will 280ba4dfef1SStephen Warren * therefore need to flush the cache-line containing the descriptor, which 281ba4dfef1SStephen Warren * will cause all other descriptors in the same cache-line to be flushed 282ba4dfef1SStephen Warren * along with it. If one of those descriptors had been written to by the 283ba4dfef1SStephen Warren * device those changes (and the associated packet) will be lost. 284ba4dfef1SStephen Warren * 285ba4dfef1SStephen Warren * To work around this, we make use of non-cached memory if available. If 286ba4dfef1SStephen Warren * descriptors are mapped uncached there's no need to manually flush them 287ba4dfef1SStephen Warren * or invalidate them. 288ba4dfef1SStephen Warren * 289ba4dfef1SStephen Warren * Note that this only applies to descriptors. The packet data buffers do 290ba4dfef1SStephen Warren * not have the same constraints since they are 1536 bytes large, so they 291ba4dfef1SStephen Warren * are unlikely to share cache-lines. 292ba4dfef1SStephen Warren */ 293ba4dfef1SStephen Warren static void *eqos_alloc_descs(unsigned int num) 294ba4dfef1SStephen Warren { 295ba4dfef1SStephen Warren #ifdef CONFIG_SYS_NONCACHED_MEMORY 296ba4dfef1SStephen Warren return (void *)noncached_alloc(EQOS_DESCRIPTORS_SIZE, 297ba4dfef1SStephen Warren EQOS_DESCRIPTOR_ALIGN); 298ba4dfef1SStephen Warren #else 299ba4dfef1SStephen Warren return memalign(EQOS_DESCRIPTOR_ALIGN, EQOS_DESCRIPTORS_SIZE); 300ba4dfef1SStephen Warren #endif 301ba4dfef1SStephen Warren } 302ba4dfef1SStephen Warren 303ba4dfef1SStephen Warren static void eqos_free_descs(void *descs) 304ba4dfef1SStephen Warren { 305ba4dfef1SStephen Warren #ifdef CONFIG_SYS_NONCACHED_MEMORY 306ba4dfef1SStephen Warren /* FIXME: noncached_alloc() has no opposite */ 307ba4dfef1SStephen Warren #else 308ba4dfef1SStephen Warren free(descs); 309ba4dfef1SStephen Warren #endif 310ba4dfef1SStephen Warren } 311ba4dfef1SStephen Warren 3127a4c4eddSChristophe Roullier static void eqos_inval_desc_tegra186(void *desc) 313ba4dfef1SStephen Warren { 314ba4dfef1SStephen Warren #ifndef CONFIG_SYS_NONCACHED_MEMORY 315ba4dfef1SStephen Warren unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); 316ba4dfef1SStephen Warren unsigned long end = ALIGN(start + EQOS_DESCRIPTOR_SIZE, 317ba4dfef1SStephen Warren ARCH_DMA_MINALIGN); 318ba4dfef1SStephen Warren 319ba4dfef1SStephen Warren invalidate_dcache_range(start, end); 320ba4dfef1SStephen Warren #endif 321ba4dfef1SStephen Warren } 322ba4dfef1SStephen Warren 323a7b3400fSFugang Duan static void eqos_inval_desc_generic(void *desc) 3247a4c4eddSChristophe Roullier { 3257a4c4eddSChristophe Roullier #ifndef CONFIG_SYS_NONCACHED_MEMORY 3267a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); 3277a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, 3287a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 3297a4c4eddSChristophe Roullier 3307a4c4eddSChristophe Roullier invalidate_dcache_range(start, end); 3317a4c4eddSChristophe Roullier #endif 3327a4c4eddSChristophe Roullier } 3337a4c4eddSChristophe Roullier 3347a4c4eddSChristophe Roullier static void eqos_flush_desc_tegra186(void *desc) 335ba4dfef1SStephen Warren { 336ba4dfef1SStephen Warren #ifndef CONFIG_SYS_NONCACHED_MEMORY 337ba4dfef1SStephen Warren flush_cache((unsigned long)desc, EQOS_DESCRIPTOR_SIZE); 338ba4dfef1SStephen Warren #endif 339ba4dfef1SStephen Warren } 340ba4dfef1SStephen Warren 341a7b3400fSFugang Duan static void eqos_flush_desc_generic(void *desc) 3427a4c4eddSChristophe Roullier { 3437a4c4eddSChristophe Roullier #ifndef CONFIG_SYS_NONCACHED_MEMORY 3447a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); 3457a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, 3467a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 3477a4c4eddSChristophe Roullier 3487a4c4eddSChristophe Roullier flush_dcache_range(start, end); 3497a4c4eddSChristophe Roullier #endif 3507a4c4eddSChristophe Roullier } 3517a4c4eddSChristophe Roullier 3527a4c4eddSChristophe Roullier static void eqos_inval_buffer_tegra186(void *buf, size_t size) 353ba4dfef1SStephen Warren { 354ba4dfef1SStephen Warren unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); 355ba4dfef1SStephen Warren unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); 356ba4dfef1SStephen Warren 357ba4dfef1SStephen Warren invalidate_dcache_range(start, end); 358ba4dfef1SStephen Warren } 359ba4dfef1SStephen Warren 360a7b3400fSFugang Duan static void eqos_inval_buffer_generic(void *buf, size_t size) 3617a4c4eddSChristophe Roullier { 3627a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); 3637a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)buf + size, 3647a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 3657a4c4eddSChristophe Roullier 3667a4c4eddSChristophe Roullier invalidate_dcache_range(start, end); 3677a4c4eddSChristophe Roullier } 3687a4c4eddSChristophe Roullier 3697a4c4eddSChristophe Roullier static void eqos_flush_buffer_tegra186(void *buf, size_t size) 370ba4dfef1SStephen Warren { 371ba4dfef1SStephen Warren flush_cache((unsigned long)buf, size); 372ba4dfef1SStephen Warren } 373ba4dfef1SStephen Warren 374a7b3400fSFugang Duan static void eqos_flush_buffer_generic(void *buf, size_t size) 3757a4c4eddSChristophe Roullier { 3767a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); 3777a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)buf + size, 3787a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 3797a4c4eddSChristophe Roullier 3807a4c4eddSChristophe Roullier flush_dcache_range(start, end); 3817a4c4eddSChristophe Roullier } 3827a4c4eddSChristophe Roullier 383ba4dfef1SStephen Warren static int eqos_mdio_wait_idle(struct eqos_priv *eqos) 384ba4dfef1SStephen Warren { 385b491b498SJon Lin return wait_for_bit_le32(&eqos->mac_regs->mdio_address, 386b491b498SJon Lin EQOS_MAC_MDIO_ADDRESS_GB, false, 387b491b498SJon Lin 1000000, true); 388ba4dfef1SStephen Warren } 389ba4dfef1SStephen Warren 390ba4dfef1SStephen Warren static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, 391ba4dfef1SStephen Warren int mdio_reg) 392ba4dfef1SStephen Warren { 393ba4dfef1SStephen Warren struct eqos_priv *eqos = bus->priv; 394ba4dfef1SStephen Warren u32 val; 395ba4dfef1SStephen Warren int ret; 396ba4dfef1SStephen Warren 397ba4dfef1SStephen Warren debug("%s(dev=%p, addr=%x, reg=%d):\n", __func__, eqos->dev, mdio_addr, 398ba4dfef1SStephen Warren mdio_reg); 399ba4dfef1SStephen Warren 400ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 401ba4dfef1SStephen Warren if (ret) { 40290aa625cSMasahiro Yamada pr_err("MDIO not idle at entry"); 403ba4dfef1SStephen Warren return ret; 404ba4dfef1SStephen Warren } 405ba4dfef1SStephen Warren 406ba4dfef1SStephen Warren val = readl(&eqos->mac_regs->mdio_address); 407ba4dfef1SStephen Warren val &= EQOS_MAC_MDIO_ADDRESS_SKAP | 408ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_C45E; 409ba4dfef1SStephen Warren val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | 410ba4dfef1SStephen Warren (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | 4117a4c4eddSChristophe Roullier (eqos->config->config_mac_mdio << 412ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | 413ba4dfef1SStephen Warren (EQOS_MAC_MDIO_ADDRESS_GOC_READ << 414ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | 415ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_GB; 416ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->mdio_address); 417ba4dfef1SStephen Warren 4187a4c4eddSChristophe Roullier udelay(eqos->config->mdio_wait); 419ba4dfef1SStephen Warren 420ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 421ba4dfef1SStephen Warren if (ret) { 42290aa625cSMasahiro Yamada pr_err("MDIO read didn't complete"); 423ba4dfef1SStephen Warren return ret; 424ba4dfef1SStephen Warren } 425ba4dfef1SStephen Warren 426ba4dfef1SStephen Warren val = readl(&eqos->mac_regs->mdio_data); 427ba4dfef1SStephen Warren val &= EQOS_MAC_MDIO_DATA_GD_MASK; 428ba4dfef1SStephen Warren 429ba4dfef1SStephen Warren debug("%s: val=%x\n", __func__, val); 430ba4dfef1SStephen Warren 431ba4dfef1SStephen Warren return val; 432ba4dfef1SStephen Warren } 433ba4dfef1SStephen Warren 434ba4dfef1SStephen Warren static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, 435ba4dfef1SStephen Warren int mdio_reg, u16 mdio_val) 436ba4dfef1SStephen Warren { 437ba4dfef1SStephen Warren struct eqos_priv *eqos = bus->priv; 438ba4dfef1SStephen Warren u32 val; 439ba4dfef1SStephen Warren int ret; 440ba4dfef1SStephen Warren 441ba4dfef1SStephen Warren debug("%s(dev=%p, addr=%x, reg=%d, val=%x):\n", __func__, eqos->dev, 442ba4dfef1SStephen Warren mdio_addr, mdio_reg, mdio_val); 443ba4dfef1SStephen Warren 444ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 445ba4dfef1SStephen Warren if (ret) { 44690aa625cSMasahiro Yamada pr_err("MDIO not idle at entry"); 447ba4dfef1SStephen Warren return ret; 448ba4dfef1SStephen Warren } 449ba4dfef1SStephen Warren 450ba4dfef1SStephen Warren writel(mdio_val, &eqos->mac_regs->mdio_data); 451ba4dfef1SStephen Warren 452ba4dfef1SStephen Warren val = readl(&eqos->mac_regs->mdio_address); 453ba4dfef1SStephen Warren val &= EQOS_MAC_MDIO_ADDRESS_SKAP | 454ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_C45E; 455ba4dfef1SStephen Warren val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | 456ba4dfef1SStephen Warren (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | 4577a4c4eddSChristophe Roullier (eqos->config->config_mac_mdio << 458ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | 459ba4dfef1SStephen Warren (EQOS_MAC_MDIO_ADDRESS_GOC_WRITE << 460ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | 461ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_GB; 462ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->mdio_address); 463ba4dfef1SStephen Warren 4647a4c4eddSChristophe Roullier udelay(eqos->config->mdio_wait); 465ba4dfef1SStephen Warren 466ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 467ba4dfef1SStephen Warren if (ret) { 46890aa625cSMasahiro Yamada pr_err("MDIO read didn't complete"); 469ba4dfef1SStephen Warren return ret; 470ba4dfef1SStephen Warren } 471ba4dfef1SStephen Warren 472ba4dfef1SStephen Warren return 0; 473ba4dfef1SStephen Warren } 474ba4dfef1SStephen Warren 475ba4dfef1SStephen Warren static int eqos_start_clks_tegra186(struct udevice *dev) 476ba4dfef1SStephen Warren { 477a7b3400fSFugang Duan #ifdef CONFIG_CLK 478ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 479ba4dfef1SStephen Warren int ret; 480ba4dfef1SStephen Warren 481ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 482ba4dfef1SStephen Warren 483ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_slave_bus); 484ba4dfef1SStephen Warren if (ret < 0) { 48590aa625cSMasahiro Yamada pr_err("clk_enable(clk_slave_bus) failed: %d", ret); 486ba4dfef1SStephen Warren goto err; 487ba4dfef1SStephen Warren } 488ba4dfef1SStephen Warren 489ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_master_bus); 490ba4dfef1SStephen Warren if (ret < 0) { 49190aa625cSMasahiro Yamada pr_err("clk_enable(clk_master_bus) failed: %d", ret); 492ba4dfef1SStephen Warren goto err_disable_clk_slave_bus; 493ba4dfef1SStephen Warren } 494ba4dfef1SStephen Warren 495ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_rx); 496ba4dfef1SStephen Warren if (ret < 0) { 49790aa625cSMasahiro Yamada pr_err("clk_enable(clk_rx) failed: %d", ret); 498ba4dfef1SStephen Warren goto err_disable_clk_master_bus; 499ba4dfef1SStephen Warren } 500ba4dfef1SStephen Warren 501ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_ptp_ref); 502ba4dfef1SStephen Warren if (ret < 0) { 50390aa625cSMasahiro Yamada pr_err("clk_enable(clk_ptp_ref) failed: %d", ret); 504ba4dfef1SStephen Warren goto err_disable_clk_rx; 505ba4dfef1SStephen Warren } 506ba4dfef1SStephen Warren 507ba4dfef1SStephen Warren ret = clk_set_rate(&eqos->clk_ptp_ref, 125 * 1000 * 1000); 508ba4dfef1SStephen Warren if (ret < 0) { 50990aa625cSMasahiro Yamada pr_err("clk_set_rate(clk_ptp_ref) failed: %d", ret); 510ba4dfef1SStephen Warren goto err_disable_clk_ptp_ref; 511ba4dfef1SStephen Warren } 512ba4dfef1SStephen Warren 513ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_tx); 514ba4dfef1SStephen Warren if (ret < 0) { 51590aa625cSMasahiro Yamada pr_err("clk_enable(clk_tx) failed: %d", ret); 516ba4dfef1SStephen Warren goto err_disable_clk_ptp_ref; 517ba4dfef1SStephen Warren } 518a7b3400fSFugang Duan #endif 519ba4dfef1SStephen Warren 520ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 521ba4dfef1SStephen Warren return 0; 522ba4dfef1SStephen Warren 523a7b3400fSFugang Duan #ifdef CONFIG_CLK 524ba4dfef1SStephen Warren err_disable_clk_ptp_ref: 525ba4dfef1SStephen Warren clk_disable(&eqos->clk_ptp_ref); 526ba4dfef1SStephen Warren err_disable_clk_rx: 527ba4dfef1SStephen Warren clk_disable(&eqos->clk_rx); 528ba4dfef1SStephen Warren err_disable_clk_master_bus: 529ba4dfef1SStephen Warren clk_disable(&eqos->clk_master_bus); 530ba4dfef1SStephen Warren err_disable_clk_slave_bus: 531ba4dfef1SStephen Warren clk_disable(&eqos->clk_slave_bus); 532ba4dfef1SStephen Warren err: 533ba4dfef1SStephen Warren debug("%s: FAILED: %d\n", __func__, ret); 534ba4dfef1SStephen Warren return ret; 535a7b3400fSFugang Duan #endif 536ba4dfef1SStephen Warren } 537ba4dfef1SStephen Warren 5387a4c4eddSChristophe Roullier static int eqos_start_clks_stm32(struct udevice *dev) 5397a4c4eddSChristophe Roullier { 540a7b3400fSFugang Duan #ifdef CONFIG_CLK 5417a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 5427a4c4eddSChristophe Roullier int ret; 5437a4c4eddSChristophe Roullier 5447a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 5457a4c4eddSChristophe Roullier 5467a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_master_bus); 5477a4c4eddSChristophe Roullier if (ret < 0) { 5487a4c4eddSChristophe Roullier pr_err("clk_enable(clk_master_bus) failed: %d", ret); 5497a4c4eddSChristophe Roullier goto err; 5507a4c4eddSChristophe Roullier } 5517a4c4eddSChristophe Roullier 552b29cefabSDavid Wu if (clk_valid(&eqos->clk_rx)) { 5537a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_rx); 5547a4c4eddSChristophe Roullier if (ret < 0) { 5557a4c4eddSChristophe Roullier pr_err("clk_enable(clk_rx) failed: %d", ret); 5567a4c4eddSChristophe Roullier goto err_disable_clk_master_bus; 5577a4c4eddSChristophe Roullier } 558b29cefabSDavid Wu } 5597a4c4eddSChristophe Roullier 560b29cefabSDavid Wu if (clk_valid(&eqos->clk_tx)) { 5617a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_tx); 5627a4c4eddSChristophe Roullier if (ret < 0) { 5637a4c4eddSChristophe Roullier pr_err("clk_enable(clk_tx) failed: %d", ret); 5647a4c4eddSChristophe Roullier goto err_disable_clk_rx; 5657a4c4eddSChristophe Roullier } 566b29cefabSDavid Wu } 5677a4c4eddSChristophe Roullier 5687a4c4eddSChristophe Roullier if (clk_valid(&eqos->clk_ck)) { 5697a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_ck); 5707a4c4eddSChristophe Roullier if (ret < 0) { 5717a4c4eddSChristophe Roullier pr_err("clk_enable(clk_ck) failed: %d", ret); 5727a4c4eddSChristophe Roullier goto err_disable_clk_tx; 5737a4c4eddSChristophe Roullier } 5747a4c4eddSChristophe Roullier } 575a7b3400fSFugang Duan #endif 5767a4c4eddSChristophe Roullier 5777a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 5787a4c4eddSChristophe Roullier return 0; 5797a4c4eddSChristophe Roullier 580a7b3400fSFugang Duan #ifdef CONFIG_CLK 5817a4c4eddSChristophe Roullier err_disable_clk_tx: 582b29cefabSDavid Wu if (clk_valid(&eqos->clk_tx)) 5837a4c4eddSChristophe Roullier clk_disable(&eqos->clk_tx); 5847a4c4eddSChristophe Roullier err_disable_clk_rx: 585b29cefabSDavid Wu if (clk_valid(&eqos->clk_rx)) 5867a4c4eddSChristophe Roullier clk_disable(&eqos->clk_rx); 5877a4c4eddSChristophe Roullier err_disable_clk_master_bus: 5887a4c4eddSChristophe Roullier clk_disable(&eqos->clk_master_bus); 5897a4c4eddSChristophe Roullier err: 5907a4c4eddSChristophe Roullier debug("%s: FAILED: %d\n", __func__, ret); 5917a4c4eddSChristophe Roullier return ret; 592a7b3400fSFugang Duan #endif 593a7b3400fSFugang Duan } 594a7b3400fSFugang Duan 595a7b3400fSFugang Duan static int eqos_start_clks_imx(struct udevice *dev) 596a7b3400fSFugang Duan { 597a7b3400fSFugang Duan return 0; 5987a4c4eddSChristophe Roullier } 5997a4c4eddSChristophe Roullier 6008aaada72SPatrick Delaunay static void eqos_stop_clks_tegra186(struct udevice *dev) 601ba4dfef1SStephen Warren { 602a7b3400fSFugang Duan #ifdef CONFIG_CLK 603ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 604ba4dfef1SStephen Warren 605ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 606ba4dfef1SStephen Warren 607ba4dfef1SStephen Warren clk_disable(&eqos->clk_tx); 608ba4dfef1SStephen Warren clk_disable(&eqos->clk_ptp_ref); 609ba4dfef1SStephen Warren clk_disable(&eqos->clk_rx); 610ba4dfef1SStephen Warren clk_disable(&eqos->clk_master_bus); 611ba4dfef1SStephen Warren clk_disable(&eqos->clk_slave_bus); 612a7b3400fSFugang Duan #endif 613ba4dfef1SStephen Warren 614ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 615ba4dfef1SStephen Warren } 616ba4dfef1SStephen Warren 6178aaada72SPatrick Delaunay static void eqos_stop_clks_stm32(struct udevice *dev) 6187a4c4eddSChristophe Roullier { 619a7b3400fSFugang Duan #ifdef CONFIG_CLK 6207a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 6217a4c4eddSChristophe Roullier 6227a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 6237a4c4eddSChristophe Roullier 624b29cefabSDavid Wu if (clk_valid(&eqos->clk_tx)) 6257a4c4eddSChristophe Roullier clk_disable(&eqos->clk_tx); 626b29cefabSDavid Wu if (clk_valid(&eqos->clk_rx)) 6277a4c4eddSChristophe Roullier clk_disable(&eqos->clk_rx); 6287a4c4eddSChristophe Roullier clk_disable(&eqos->clk_master_bus); 6297a4c4eddSChristophe Roullier if (clk_valid(&eqos->clk_ck)) 6307a4c4eddSChristophe Roullier clk_disable(&eqos->clk_ck); 631a7b3400fSFugang Duan #endif 6327a4c4eddSChristophe Roullier 6337a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 6347a4c4eddSChristophe Roullier } 6357a4c4eddSChristophe Roullier 636a7b3400fSFugang Duan static void eqos_stop_clks_imx(struct udevice *dev) 637a7b3400fSFugang Duan { 638a7b3400fSFugang Duan /* empty */ 639a7b3400fSFugang Duan } 640a7b3400fSFugang Duan 641ba4dfef1SStephen Warren static int eqos_start_resets_tegra186(struct udevice *dev) 642ba4dfef1SStephen Warren { 643ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 644ba4dfef1SStephen Warren int ret; 645ba4dfef1SStephen Warren 646ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 647ba4dfef1SStephen Warren 648ba4dfef1SStephen Warren ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); 649ba4dfef1SStephen Warren if (ret < 0) { 65090aa625cSMasahiro Yamada pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret); 651ba4dfef1SStephen Warren return ret; 652ba4dfef1SStephen Warren } 653ba4dfef1SStephen Warren 654ba4dfef1SStephen Warren udelay(2); 655ba4dfef1SStephen Warren 656ba4dfef1SStephen Warren ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); 657ba4dfef1SStephen Warren if (ret < 0) { 65890aa625cSMasahiro Yamada pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret); 659ba4dfef1SStephen Warren return ret; 660ba4dfef1SStephen Warren } 661ba4dfef1SStephen Warren 662ba4dfef1SStephen Warren ret = reset_assert(&eqos->reset_ctl); 663ba4dfef1SStephen Warren if (ret < 0) { 66490aa625cSMasahiro Yamada pr_err("reset_assert() failed: %d", ret); 665ba4dfef1SStephen Warren return ret; 666ba4dfef1SStephen Warren } 667ba4dfef1SStephen Warren 668ba4dfef1SStephen Warren udelay(2); 669ba4dfef1SStephen Warren 670ba4dfef1SStephen Warren ret = reset_deassert(&eqos->reset_ctl); 671ba4dfef1SStephen Warren if (ret < 0) { 67290aa625cSMasahiro Yamada pr_err("reset_deassert() failed: %d", ret); 673ba4dfef1SStephen Warren return ret; 674ba4dfef1SStephen Warren } 675ba4dfef1SStephen Warren 676ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 677ba4dfef1SStephen Warren return 0; 678ba4dfef1SStephen Warren } 679ba4dfef1SStephen Warren 6807a4c4eddSChristophe Roullier static int eqos_start_resets_stm32(struct udevice *dev) 6817a4c4eddSChristophe Roullier { 6825bd3c538SChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 6835bd3c538SChristophe Roullier int ret; 6845bd3c538SChristophe Roullier 6855bd3c538SChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 6865bd3c538SChristophe Roullier if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { 68713105a0bSDavid Wu ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); 68813105a0bSDavid Wu if (ret < 0) { 68913105a0bSDavid Wu pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", 69013105a0bSDavid Wu ret); 69113105a0bSDavid Wu return ret; 69213105a0bSDavid Wu } 69313105a0bSDavid Wu 69413105a0bSDavid Wu udelay(eqos->reset_delays[0]); 69513105a0bSDavid Wu 6965bd3c538SChristophe Roullier ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); 6975bd3c538SChristophe Roullier if (ret < 0) { 6985bd3c538SChristophe Roullier pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", 6995bd3c538SChristophe Roullier ret); 7005bd3c538SChristophe Roullier return ret; 7015bd3c538SChristophe Roullier } 7025bd3c538SChristophe Roullier 70313105a0bSDavid Wu udelay(eqos->reset_delays[1]); 7045bd3c538SChristophe Roullier 7055bd3c538SChristophe Roullier ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); 7065bd3c538SChristophe Roullier if (ret < 0) { 7075bd3c538SChristophe Roullier pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", 7085bd3c538SChristophe Roullier ret); 7095bd3c538SChristophe Roullier return ret; 7105bd3c538SChristophe Roullier } 71113105a0bSDavid Wu 71213105a0bSDavid Wu udelay(eqos->reset_delays[2]); 7135bd3c538SChristophe Roullier } 7145bd3c538SChristophe Roullier debug("%s: OK\n", __func__); 7155bd3c538SChristophe Roullier 7167a4c4eddSChristophe Roullier return 0; 7177a4c4eddSChristophe Roullier } 7187a4c4eddSChristophe Roullier 719a7b3400fSFugang Duan static int eqos_start_resets_imx(struct udevice *dev) 720a7b3400fSFugang Duan { 721a7b3400fSFugang Duan return 0; 722a7b3400fSFugang Duan } 723a7b3400fSFugang Duan 724ba4dfef1SStephen Warren static int eqos_stop_resets_tegra186(struct udevice *dev) 725ba4dfef1SStephen Warren { 726ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 727ba4dfef1SStephen Warren 728ba4dfef1SStephen Warren reset_assert(&eqos->reset_ctl); 729ba4dfef1SStephen Warren dm_gpio_set_value(&eqos->phy_reset_gpio, 1); 730ba4dfef1SStephen Warren 731ba4dfef1SStephen Warren return 0; 732ba4dfef1SStephen Warren } 733ba4dfef1SStephen Warren 7347a4c4eddSChristophe Roullier static int eqos_stop_resets_stm32(struct udevice *dev) 7357a4c4eddSChristophe Roullier { 7365bd3c538SChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 7375bd3c538SChristophe Roullier int ret; 7385bd3c538SChristophe Roullier 7395bd3c538SChristophe Roullier if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { 7405bd3c538SChristophe Roullier ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); 7415bd3c538SChristophe Roullier if (ret < 0) { 7425bd3c538SChristophe Roullier pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", 7435bd3c538SChristophe Roullier ret); 7445bd3c538SChristophe Roullier return ret; 7455bd3c538SChristophe Roullier } 7465bd3c538SChristophe Roullier } 7475bd3c538SChristophe Roullier 7487a4c4eddSChristophe Roullier return 0; 7497a4c4eddSChristophe Roullier } 7507a4c4eddSChristophe Roullier 751a7b3400fSFugang Duan static int eqos_stop_resets_imx(struct udevice *dev) 752a7b3400fSFugang Duan { 753a7b3400fSFugang Duan return 0; 754a7b3400fSFugang Duan } 755a7b3400fSFugang Duan 756ba4dfef1SStephen Warren static int eqos_calibrate_pads_tegra186(struct udevice *dev) 757ba4dfef1SStephen Warren { 758ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 759ba4dfef1SStephen Warren int ret; 760ba4dfef1SStephen Warren 761ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 762ba4dfef1SStephen Warren 763ba4dfef1SStephen Warren setbits_le32(&eqos->tegra186_regs->sdmemcomppadctrl, 764ba4dfef1SStephen Warren EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD); 765ba4dfef1SStephen Warren 766ba4dfef1SStephen Warren udelay(1); 767ba4dfef1SStephen Warren 768ba4dfef1SStephen Warren setbits_le32(&eqos->tegra186_regs->auto_cal_config, 769ba4dfef1SStephen Warren EQOS_AUTO_CAL_CONFIG_START | EQOS_AUTO_CAL_CONFIG_ENABLE); 770ba4dfef1SStephen Warren 771b491b498SJon Lin ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status, 772ba4dfef1SStephen Warren EQOS_AUTO_CAL_STATUS_ACTIVE, true, 10, false); 773ba4dfef1SStephen Warren if (ret) { 77490aa625cSMasahiro Yamada pr_err("calibrate didn't start"); 775ba4dfef1SStephen Warren goto failed; 776ba4dfef1SStephen Warren } 777ba4dfef1SStephen Warren 778b491b498SJon Lin ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status, 779ba4dfef1SStephen Warren EQOS_AUTO_CAL_STATUS_ACTIVE, false, 10, false); 780ba4dfef1SStephen Warren if (ret) { 78190aa625cSMasahiro Yamada pr_err("calibrate didn't finish"); 782ba4dfef1SStephen Warren goto failed; 783ba4dfef1SStephen Warren } 784ba4dfef1SStephen Warren 785ba4dfef1SStephen Warren ret = 0; 786ba4dfef1SStephen Warren 787ba4dfef1SStephen Warren failed: 788ba4dfef1SStephen Warren clrbits_le32(&eqos->tegra186_regs->sdmemcomppadctrl, 789ba4dfef1SStephen Warren EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD); 790ba4dfef1SStephen Warren 791ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 792ba4dfef1SStephen Warren 793ba4dfef1SStephen Warren return ret; 794ba4dfef1SStephen Warren } 795ba4dfef1SStephen Warren 796ba4dfef1SStephen Warren static int eqos_disable_calibration_tegra186(struct udevice *dev) 797ba4dfef1SStephen Warren { 798ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 799ba4dfef1SStephen Warren 800ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 801ba4dfef1SStephen Warren 802ba4dfef1SStephen Warren clrbits_le32(&eqos->tegra186_regs->auto_cal_config, 803ba4dfef1SStephen Warren EQOS_AUTO_CAL_CONFIG_ENABLE); 804ba4dfef1SStephen Warren 805ba4dfef1SStephen Warren return 0; 806ba4dfef1SStephen Warren } 807ba4dfef1SStephen Warren 808ba4dfef1SStephen Warren static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev) 809ba4dfef1SStephen Warren { 810a7b3400fSFugang Duan #ifdef CONFIG_CLK 811ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 812ba4dfef1SStephen Warren 813ba4dfef1SStephen Warren return clk_get_rate(&eqos->clk_slave_bus); 814a7b3400fSFugang Duan #else 815a7b3400fSFugang Duan return 0; 816a7b3400fSFugang Duan #endif 817ba4dfef1SStephen Warren } 818ba4dfef1SStephen Warren 8197a4c4eddSChristophe Roullier static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) 8207a4c4eddSChristophe Roullier { 821a7b3400fSFugang Duan #ifdef CONFIG_CLK 8227a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 8237a4c4eddSChristophe Roullier 8247a4c4eddSChristophe Roullier return clk_get_rate(&eqos->clk_master_bus); 825a7b3400fSFugang Duan #else 826a7b3400fSFugang Duan return 0; 827a7b3400fSFugang Duan #endif 828a7b3400fSFugang Duan } 829a7b3400fSFugang Duan 830ad018a0cSFugang Duan __weak u32 imx_get_eqos_csr_clk(void) 831ad018a0cSFugang Duan { 832ad018a0cSFugang Duan return 100 * 1000000; 833ad018a0cSFugang Duan } 834ad018a0cSFugang Duan __weak int imx_eqos_txclk_set_rate(unsigned long rate) 835ad018a0cSFugang Duan { 836ad018a0cSFugang Duan return 0; 837ad018a0cSFugang Duan } 838ad018a0cSFugang Duan 839a7b3400fSFugang Duan static ulong eqos_get_tick_clk_rate_imx(struct udevice *dev) 840a7b3400fSFugang Duan { 841ad018a0cSFugang Duan return imx_get_eqos_csr_clk(); 8427a4c4eddSChristophe Roullier } 8437a4c4eddSChristophe Roullier 8447a4c4eddSChristophe Roullier static int eqos_calibrate_pads_stm32(struct udevice *dev) 8457a4c4eddSChristophe Roullier { 8467a4c4eddSChristophe Roullier return 0; 8477a4c4eddSChristophe Roullier } 8487a4c4eddSChristophe Roullier 849a7b3400fSFugang Duan static int eqos_calibrate_pads_imx(struct udevice *dev) 850a7b3400fSFugang Duan { 851a7b3400fSFugang Duan return 0; 852a7b3400fSFugang Duan } 853a7b3400fSFugang Duan 8547a4c4eddSChristophe Roullier static int eqos_disable_calibration_stm32(struct udevice *dev) 8557a4c4eddSChristophe Roullier { 8567a4c4eddSChristophe Roullier return 0; 8577a4c4eddSChristophe Roullier } 8587a4c4eddSChristophe Roullier 859a7b3400fSFugang Duan static int eqos_disable_calibration_imx(struct udevice *dev) 860a7b3400fSFugang Duan { 861a7b3400fSFugang Duan return 0; 862a7b3400fSFugang Duan } 863a7b3400fSFugang Duan 864ba4dfef1SStephen Warren static int eqos_set_full_duplex(struct udevice *dev) 865ba4dfef1SStephen Warren { 866ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 867ba4dfef1SStephen Warren 868ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 869ba4dfef1SStephen Warren 870ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->configuration, EQOS_MAC_CONFIGURATION_DM); 871ba4dfef1SStephen Warren 872ba4dfef1SStephen Warren return 0; 873ba4dfef1SStephen Warren } 874ba4dfef1SStephen Warren 875ba4dfef1SStephen Warren static int eqos_set_half_duplex(struct udevice *dev) 876ba4dfef1SStephen Warren { 877ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 878ba4dfef1SStephen Warren 879ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 880ba4dfef1SStephen Warren 881ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->configuration, EQOS_MAC_CONFIGURATION_DM); 882ba4dfef1SStephen Warren 883ba4dfef1SStephen Warren /* WAR: Flush TX queue when switching to half-duplex */ 884ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->txq0_operation_mode, 885ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_FTQ); 886ba4dfef1SStephen Warren 887ba4dfef1SStephen Warren return 0; 888ba4dfef1SStephen Warren } 889ba4dfef1SStephen Warren 890ba4dfef1SStephen Warren static int eqos_set_gmii_speed(struct udevice *dev) 891ba4dfef1SStephen Warren { 892ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 893ba4dfef1SStephen Warren 894ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 895ba4dfef1SStephen Warren 896ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->configuration, 897ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_PS | EQOS_MAC_CONFIGURATION_FES); 898ba4dfef1SStephen Warren 899ba4dfef1SStephen Warren return 0; 900ba4dfef1SStephen Warren } 901ba4dfef1SStephen Warren 902ba4dfef1SStephen Warren static int eqos_set_mii_speed_100(struct udevice *dev) 903ba4dfef1SStephen Warren { 904ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 905ba4dfef1SStephen Warren 906ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 907ba4dfef1SStephen Warren 908ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->configuration, 909ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_PS | EQOS_MAC_CONFIGURATION_FES); 910ba4dfef1SStephen Warren 911ba4dfef1SStephen Warren return 0; 912ba4dfef1SStephen Warren } 913ba4dfef1SStephen Warren 914ba4dfef1SStephen Warren static int eqos_set_mii_speed_10(struct udevice *dev) 915ba4dfef1SStephen Warren { 916ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 917ba4dfef1SStephen Warren 918ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 919ba4dfef1SStephen Warren 920ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mac_regs->configuration, 921ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_FES, EQOS_MAC_CONFIGURATION_PS); 922ba4dfef1SStephen Warren 923ba4dfef1SStephen Warren return 0; 924ba4dfef1SStephen Warren } 925ba4dfef1SStephen Warren 926ba4dfef1SStephen Warren static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) 927ba4dfef1SStephen Warren { 928a7b3400fSFugang Duan #ifdef CONFIG_CLK 929ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 930ba4dfef1SStephen Warren ulong rate; 931ba4dfef1SStephen Warren int ret; 932ba4dfef1SStephen Warren 933ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 934ba4dfef1SStephen Warren 935ba4dfef1SStephen Warren switch (eqos->phy->speed) { 936ba4dfef1SStephen Warren case SPEED_1000: 937ba4dfef1SStephen Warren rate = 125 * 1000 * 1000; 938ba4dfef1SStephen Warren break; 939ba4dfef1SStephen Warren case SPEED_100: 940ba4dfef1SStephen Warren rate = 25 * 1000 * 1000; 941ba4dfef1SStephen Warren break; 942ba4dfef1SStephen Warren case SPEED_10: 943ba4dfef1SStephen Warren rate = 2.5 * 1000 * 1000; 944ba4dfef1SStephen Warren break; 945ba4dfef1SStephen Warren default: 94690aa625cSMasahiro Yamada pr_err("invalid speed %d", eqos->phy->speed); 947ba4dfef1SStephen Warren return -EINVAL; 948ba4dfef1SStephen Warren } 949ba4dfef1SStephen Warren 950ba4dfef1SStephen Warren ret = clk_set_rate(&eqos->clk_tx, rate); 951ba4dfef1SStephen Warren if (ret < 0) { 95290aa625cSMasahiro Yamada pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret); 953ba4dfef1SStephen Warren return ret; 954ba4dfef1SStephen Warren } 955a7b3400fSFugang Duan #endif 956ba4dfef1SStephen Warren 957ba4dfef1SStephen Warren return 0; 958ba4dfef1SStephen Warren } 959ba4dfef1SStephen Warren 9607a4c4eddSChristophe Roullier static int eqos_set_tx_clk_speed_stm32(struct udevice *dev) 9617a4c4eddSChristophe Roullier { 9627a4c4eddSChristophe Roullier return 0; 9637a4c4eddSChristophe Roullier } 9647a4c4eddSChristophe Roullier 965a7b3400fSFugang Duan static int eqos_set_tx_clk_speed_imx(struct udevice *dev) 966a7b3400fSFugang Duan { 967ad018a0cSFugang Duan struct eqos_priv *eqos = dev_get_priv(dev); 968ad018a0cSFugang Duan ulong rate; 969ad018a0cSFugang Duan int ret; 970ad018a0cSFugang Duan 971ad018a0cSFugang Duan debug("%s(dev=%p):\n", __func__, dev); 972ad018a0cSFugang Duan 973ad018a0cSFugang Duan switch (eqos->phy->speed) { 974ad018a0cSFugang Duan case SPEED_1000: 975ad018a0cSFugang Duan rate = 125 * 1000 * 1000; 976ad018a0cSFugang Duan break; 977ad018a0cSFugang Duan case SPEED_100: 978ad018a0cSFugang Duan rate = 25 * 1000 * 1000; 979ad018a0cSFugang Duan break; 980ad018a0cSFugang Duan case SPEED_10: 981ad018a0cSFugang Duan rate = 2.5 * 1000 * 1000; 982ad018a0cSFugang Duan break; 983ad018a0cSFugang Duan default: 984ad018a0cSFugang Duan pr_err("invalid speed %d", eqos->phy->speed); 985ad018a0cSFugang Duan return -EINVAL; 986ad018a0cSFugang Duan } 987ad018a0cSFugang Duan 988ad018a0cSFugang Duan ret = imx_eqos_txclk_set_rate(rate); 989ad018a0cSFugang Duan if (ret < 0) { 990ad018a0cSFugang Duan pr_err("imx (tx_clk, %lu) failed: %d", rate, ret); 991ad018a0cSFugang Duan return ret; 992ad018a0cSFugang Duan } 993ad018a0cSFugang Duan 994a7b3400fSFugang Duan return 0; 995a7b3400fSFugang Duan } 996a7b3400fSFugang Duan 997ba4dfef1SStephen Warren static int eqos_adjust_link(struct udevice *dev) 998ba4dfef1SStephen Warren { 999ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1000ba4dfef1SStephen Warren int ret; 1001ba4dfef1SStephen Warren bool en_calibration; 1002ba4dfef1SStephen Warren 1003ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1004ba4dfef1SStephen Warren 1005ba4dfef1SStephen Warren if (eqos->phy->duplex) 1006ba4dfef1SStephen Warren ret = eqos_set_full_duplex(dev); 1007ba4dfef1SStephen Warren else 1008ba4dfef1SStephen Warren ret = eqos_set_half_duplex(dev); 1009ba4dfef1SStephen Warren if (ret < 0) { 101090aa625cSMasahiro Yamada pr_err("eqos_set_*_duplex() failed: %d", ret); 1011ba4dfef1SStephen Warren return ret; 1012ba4dfef1SStephen Warren } 1013ba4dfef1SStephen Warren 1014ba4dfef1SStephen Warren switch (eqos->phy->speed) { 1015ba4dfef1SStephen Warren case SPEED_1000: 1016ba4dfef1SStephen Warren en_calibration = true; 1017ba4dfef1SStephen Warren ret = eqos_set_gmii_speed(dev); 1018ba4dfef1SStephen Warren break; 1019ba4dfef1SStephen Warren case SPEED_100: 1020ba4dfef1SStephen Warren en_calibration = true; 1021ba4dfef1SStephen Warren ret = eqos_set_mii_speed_100(dev); 1022ba4dfef1SStephen Warren break; 1023ba4dfef1SStephen Warren case SPEED_10: 1024ba4dfef1SStephen Warren en_calibration = false; 1025ba4dfef1SStephen Warren ret = eqos_set_mii_speed_10(dev); 1026ba4dfef1SStephen Warren break; 1027ba4dfef1SStephen Warren default: 102890aa625cSMasahiro Yamada pr_err("invalid speed %d", eqos->phy->speed); 1029ba4dfef1SStephen Warren return -EINVAL; 1030ba4dfef1SStephen Warren } 1031ba4dfef1SStephen Warren if (ret < 0) { 103290aa625cSMasahiro Yamada pr_err("eqos_set_*mii_speed*() failed: %d", ret); 1033ba4dfef1SStephen Warren return ret; 1034ba4dfef1SStephen Warren } 1035ba4dfef1SStephen Warren 1036ba4dfef1SStephen Warren if (en_calibration) { 10377a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_calibrate_pads(dev); 1038ba4dfef1SStephen Warren if (ret < 0) { 10397a4c4eddSChristophe Roullier pr_err("eqos_calibrate_pads() failed: %d", 10407a4c4eddSChristophe Roullier ret); 1041ba4dfef1SStephen Warren return ret; 1042ba4dfef1SStephen Warren } 1043ba4dfef1SStephen Warren } else { 10447a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_disable_calibration(dev); 1045ba4dfef1SStephen Warren if (ret < 0) { 10467a4c4eddSChristophe Roullier pr_err("eqos_disable_calibration() failed: %d", 1047ba4dfef1SStephen Warren ret); 1048ba4dfef1SStephen Warren return ret; 1049ba4dfef1SStephen Warren } 1050ba4dfef1SStephen Warren } 10517a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_set_tx_clk_speed(dev); 1052ba4dfef1SStephen Warren if (ret < 0) { 10537a4c4eddSChristophe Roullier pr_err("eqos_set_tx_clk_speed() failed: %d", ret); 1054ba4dfef1SStephen Warren return ret; 1055ba4dfef1SStephen Warren } 1056ba4dfef1SStephen Warren 1057ba4dfef1SStephen Warren return 0; 1058ba4dfef1SStephen Warren } 1059ba4dfef1SStephen Warren 106023ca6f74SDavid Wu int eqos_write_hwaddr(struct udevice *dev) 1061ba4dfef1SStephen Warren { 1062ba4dfef1SStephen Warren struct eth_pdata *plat = dev_get_platdata(dev); 1063ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1064ba4dfef1SStephen Warren uint32_t val; 1065ba4dfef1SStephen Warren 1066ba4dfef1SStephen Warren /* 1067ba4dfef1SStephen Warren * This function may be called before start() or after stop(). At that 1068ba4dfef1SStephen Warren * time, on at least some configurations of the EQoS HW, all clocks to 1069ba4dfef1SStephen Warren * the EQoS HW block will be stopped, and a reset signal applied. If 1070ba4dfef1SStephen Warren * any register access is attempted in this state, bus timeouts or CPU 1071ba4dfef1SStephen Warren * hangs may occur. This check prevents that. 1072ba4dfef1SStephen Warren * 1073ba4dfef1SStephen Warren * A simple solution to this problem would be to not implement 1074ba4dfef1SStephen Warren * write_hwaddr(), since start() always writes the MAC address into HW 1075ba4dfef1SStephen Warren * anyway. However, it is desirable to implement write_hwaddr() to 1076ba4dfef1SStephen Warren * support the case of SW that runs subsequent to U-Boot which expects 1077ba4dfef1SStephen Warren * the MAC address to already be programmed into the EQoS registers, 1078ba4dfef1SStephen Warren * which must happen irrespective of whether the U-Boot user (or 1079ba4dfef1SStephen Warren * scripts) actually made use of the EQoS device, and hence 1080ba4dfef1SStephen Warren * irrespective of whether start() was ever called. 1081ba4dfef1SStephen Warren * 1082ba4dfef1SStephen Warren * Note that this requirement by subsequent SW is not valid for 1083ba4dfef1SStephen Warren * Tegra186, and is likely not valid for any non-PCI instantiation of 1084ba4dfef1SStephen Warren * the EQoS HW block. This function is implemented solely as 1085ba4dfef1SStephen Warren * future-proofing with the expectation the driver will eventually be 1086ba4dfef1SStephen Warren * ported to some system where the expectation above is true. 1087ba4dfef1SStephen Warren */ 1088ba4dfef1SStephen Warren if (!eqos->config->reg_access_always_ok && !eqos->reg_access_ok) 1089ba4dfef1SStephen Warren return 0; 1090ba4dfef1SStephen Warren 1091ba4dfef1SStephen Warren /* Update the MAC address */ 1092ba4dfef1SStephen Warren val = (plat->enetaddr[5] << 8) | 1093ba4dfef1SStephen Warren (plat->enetaddr[4]); 1094ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->address0_high); 1095ba4dfef1SStephen Warren val = (plat->enetaddr[3] << 24) | 1096ba4dfef1SStephen Warren (plat->enetaddr[2] << 16) | 1097ba4dfef1SStephen Warren (plat->enetaddr[1] << 8) | 1098ba4dfef1SStephen Warren (plat->enetaddr[0]); 1099ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->address0_low); 1100ba4dfef1SStephen Warren 1101ba4dfef1SStephen Warren return 0; 1102ba4dfef1SStephen Warren } 1103ba4dfef1SStephen Warren 11044d0fb6f0SYe Li static int eqos_read_rom_hwaddr(struct udevice *dev) 11054d0fb6f0SYe Li { 11064d0fb6f0SYe Li struct eth_pdata *pdata = dev_get_platdata(dev); 11074d0fb6f0SYe Li 11084d0fb6f0SYe Li #ifdef CONFIG_ARCH_IMX8M 11094d0fb6f0SYe Li imx_get_mac_from_fuse(dev->req_seq, pdata->enetaddr); 11104d0fb6f0SYe Li #endif 11114d0fb6f0SYe Li return !is_valid_ethaddr(pdata->enetaddr); 11124d0fb6f0SYe Li } 11134d0fb6f0SYe Li 111423ca6f74SDavid Wu int eqos_init(struct udevice *dev) 1115ba4dfef1SStephen Warren { 1116ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1117a494aeaaSDavid Wu int ret, limit = 10; 1118ba4dfef1SStephen Warren ulong rate; 11195bcea7aaSDavid Wu u32 val; 1120ba4dfef1SStephen Warren 1121ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1122ba4dfef1SStephen Warren 1123e2d58431SDavid Wu if (eqos->config->ops->eqos_start_clks) { 11247a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_start_clks(dev); 1125ba4dfef1SStephen Warren if (ret < 0) { 11267a4c4eddSChristophe Roullier pr_err("eqos_start_clks() failed: %d", ret); 1127ba4dfef1SStephen Warren goto err; 1128ba4dfef1SStephen Warren } 1129e2d58431SDavid Wu } 1130ba4dfef1SStephen Warren 11317a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_start_resets(dev); 1132ba4dfef1SStephen Warren if (ret < 0) { 11337a4c4eddSChristophe Roullier pr_err("eqos_start_resets() failed: %d", ret); 1134ba4dfef1SStephen Warren goto err_stop_clks; 1135ba4dfef1SStephen Warren } 1136ba4dfef1SStephen Warren 1137ba4dfef1SStephen Warren udelay(10); 1138ba4dfef1SStephen Warren 1139ba4dfef1SStephen Warren eqos->reg_access_ok = true; 1140ba4dfef1SStephen Warren 1141a494aeaaSDavid Wu /* DMA SW reset */ 1142a494aeaaSDavid Wu val = readl(&eqos->dma_regs->mode); 1143a494aeaaSDavid Wu val |= EQOS_DMA_MODE_SWR; 1144a494aeaaSDavid Wu writel(val, &eqos->dma_regs->mode); 1145a494aeaaSDavid Wu while (limit--) { 1146a494aeaaSDavid Wu if (!(readl(&eqos->dma_regs->mode) & EQOS_DMA_MODE_SWR)) 1147a494aeaaSDavid Wu break; 1148a494aeaaSDavid Wu mdelay(10); 1149a494aeaaSDavid Wu } 1150a494aeaaSDavid Wu 1151a494aeaaSDavid Wu if (limit < 0) { 115290aa625cSMasahiro Yamada pr_err("EQOS_DMA_MODE_SWR stuck"); 1153ba4dfef1SStephen Warren goto err_stop_resets; 1154ba4dfef1SStephen Warren } 1155ba4dfef1SStephen Warren 11567a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_calibrate_pads(dev); 1157ba4dfef1SStephen Warren if (ret < 0) { 11587a4c4eddSChristophe Roullier pr_err("eqos_calibrate_pads() failed: %d", ret); 1159ba4dfef1SStephen Warren goto err_stop_resets; 1160ba4dfef1SStephen Warren } 11617a4c4eddSChristophe Roullier rate = eqos->config->ops->eqos_get_tick_clk_rate(dev); 1162ba4dfef1SStephen Warren 1163ba4dfef1SStephen Warren val = (rate / 1000000) - 1; 1164ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->us_tic_counter); 1165ba4dfef1SStephen Warren 11667a4c4eddSChristophe Roullier /* 11677a4c4eddSChristophe Roullier * if PHY was already connected and configured, 11687a4c4eddSChristophe Roullier * don't need to reconnect/reconfigure again 11697a4c4eddSChristophe Roullier */ 11707a4c4eddSChristophe Roullier if (!eqos->phy) { 11718e3eceb0SYe Li int addr = -1; 11728e3eceb0SYe Li #ifdef CONFIG_DM_ETH_PHY 11738e3eceb0SYe Li addr = eth_phy_get_addr(dev); 11748e3eceb0SYe Li #endif 11758e3eceb0SYe Li #ifdef DWC_NET_PHYADDR 11768e3eceb0SYe Li addr = DWC_NET_PHYADDR; 11778e3eceb0SYe Li #endif 11788e3eceb0SYe Li eqos->phy = phy_connect(eqos->mii, addr, dev, 1179bbbbc81cSDavid Wu eqos->config->ops->eqos_get_interface(dev)); 1180ba4dfef1SStephen Warren if (!eqos->phy) { 118190aa625cSMasahiro Yamada pr_err("phy_connect() failed"); 1182ba4dfef1SStephen Warren goto err_stop_resets; 1183ba4dfef1SStephen Warren } 118483d31c08SPatrick Delaunay 118583d31c08SPatrick Delaunay if (eqos->max_speed) { 118683d31c08SPatrick Delaunay ret = phy_set_supported(eqos->phy, eqos->max_speed); 118783d31c08SPatrick Delaunay if (ret) { 118883d31c08SPatrick Delaunay pr_err("phy_set_supported() failed: %d", ret); 118983d31c08SPatrick Delaunay goto err_shutdown_phy; 119083d31c08SPatrick Delaunay } 119183d31c08SPatrick Delaunay } 119283d31c08SPatrick Delaunay 1193ba4dfef1SStephen Warren ret = phy_config(eqos->phy); 1194ba4dfef1SStephen Warren if (ret < 0) { 119590aa625cSMasahiro Yamada pr_err("phy_config() failed: %d", ret); 1196ba4dfef1SStephen Warren goto err_shutdown_phy; 1197ba4dfef1SStephen Warren } 11987a4c4eddSChristophe Roullier } 11997a4c4eddSChristophe Roullier 1200ba4dfef1SStephen Warren ret = phy_startup(eqos->phy); 1201ba4dfef1SStephen Warren if (ret < 0) { 120290aa625cSMasahiro Yamada pr_err("phy_startup() failed: %d", ret); 1203ba4dfef1SStephen Warren goto err_shutdown_phy; 1204ba4dfef1SStephen Warren } 1205ba4dfef1SStephen Warren 1206ba4dfef1SStephen Warren if (!eqos->phy->link) { 120790aa625cSMasahiro Yamada pr_err("No link"); 1208ba4dfef1SStephen Warren goto err_shutdown_phy; 1209ba4dfef1SStephen Warren } 1210ba4dfef1SStephen Warren 1211ba4dfef1SStephen Warren ret = eqos_adjust_link(dev); 1212ba4dfef1SStephen Warren if (ret < 0) { 121390aa625cSMasahiro Yamada pr_err("eqos_adjust_link() failed: %d", ret); 1214ba4dfef1SStephen Warren goto err_shutdown_phy; 1215ba4dfef1SStephen Warren } 1216ba4dfef1SStephen Warren 12175bcea7aaSDavid Wu debug("%s: OK\n", __func__); 12185bcea7aaSDavid Wu return 0; 12195bcea7aaSDavid Wu 12205bcea7aaSDavid Wu err_shutdown_phy: 12215bcea7aaSDavid Wu phy_shutdown(eqos->phy); 12225bcea7aaSDavid Wu err_stop_resets: 12235bcea7aaSDavid Wu eqos->config->ops->eqos_stop_resets(dev); 12245bcea7aaSDavid Wu err_stop_clks: 1225e2d58431SDavid Wu if (eqos->config->ops->eqos_stop_clks) 12265bcea7aaSDavid Wu eqos->config->ops->eqos_stop_clks(dev); 12275bcea7aaSDavid Wu err: 12285bcea7aaSDavid Wu pr_err("FAILED: %d", ret); 12295bcea7aaSDavid Wu return ret; 12305bcea7aaSDavid Wu } 12315bcea7aaSDavid Wu 123223ca6f74SDavid Wu void eqos_enable(struct udevice *dev) 12335bcea7aaSDavid Wu { 12345bcea7aaSDavid Wu struct eqos_priv *eqos = dev_get_priv(dev); 12355bcea7aaSDavid Wu u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl; 12365bcea7aaSDavid Wu ulong last_rx_desc; 12375bcea7aaSDavid Wu int i; 12385bcea7aaSDavid Wu 12395bcea7aaSDavid Wu eqos->tx_desc_idx = 0; 12405bcea7aaSDavid Wu eqos->rx_desc_idx = 0; 12415bcea7aaSDavid Wu 1242ba4dfef1SStephen Warren /* Configure MTL */ 1243a7b3400fSFugang Duan writel(0x60, &eqos->mtl_regs->txq0_quantum_weight - 0x100); 1244ba4dfef1SStephen Warren 1245ba4dfef1SStephen Warren /* Enable Store and Forward mode for TX */ 1246ba4dfef1SStephen Warren /* Program Tx operating mode */ 1247ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->txq0_operation_mode, 1248ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TSF | 1249ba4dfef1SStephen Warren (EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED << 1250ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT)); 1251ba4dfef1SStephen Warren 1252ba4dfef1SStephen Warren /* Transmit Queue weight */ 1253ba4dfef1SStephen Warren writel(0x10, &eqos->mtl_regs->txq0_quantum_weight); 1254ba4dfef1SStephen Warren 1255ba4dfef1SStephen Warren /* Enable Store and Forward mode for RX, since no jumbo frame */ 1256ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1257a7b3400fSFugang Duan EQOS_MTL_RXQ0_OPERATION_MODE_RSF | 1258a7b3400fSFugang Duan EQOS_MTL_RXQ0_OPERATION_MODE_FEP | 1259a7b3400fSFugang Duan EQOS_MTL_RXQ0_OPERATION_MODE_FUP); 1260ba4dfef1SStephen Warren 1261ba4dfef1SStephen Warren /* Transmit/Receive queue fifo size; use all RAM for 1 queue */ 1262ba4dfef1SStephen Warren val = readl(&eqos->mac_regs->hw_feature1); 1263ba4dfef1SStephen Warren tx_fifo_sz = (val >> EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT) & 1264ba4dfef1SStephen Warren EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK; 1265ba4dfef1SStephen Warren rx_fifo_sz = (val >> EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT) & 1266ba4dfef1SStephen Warren EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK; 1267ba4dfef1SStephen Warren 1268ba4dfef1SStephen Warren /* 1269ba4dfef1SStephen Warren * r/tx_fifo_sz is encoded as log2(n / 128). Undo that by shifting. 1270ba4dfef1SStephen Warren * r/tqs is encoded as (n / 256) - 1. 1271ba4dfef1SStephen Warren */ 1272ba4dfef1SStephen Warren tqs = (128 << tx_fifo_sz) / 256 - 1; 1273ba4dfef1SStephen Warren rqs = (128 << rx_fifo_sz) / 256 - 1; 1274ba4dfef1SStephen Warren 1275ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mtl_regs->txq0_operation_mode, 1276ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TQS_MASK << 1277ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT, 1278ba4dfef1SStephen Warren tqs << EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT); 1279ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1280ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RQS_MASK << 1281ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT, 1282ba4dfef1SStephen Warren rqs << EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT); 1283ba4dfef1SStephen Warren 1284ba4dfef1SStephen Warren /* Flow control used only if each channel gets 4KB or more FIFO */ 1285ba4dfef1SStephen Warren if (rqs >= ((4096 / 256) - 1)) { 1286ba4dfef1SStephen Warren u32 rfd, rfa; 1287ba4dfef1SStephen Warren 1288ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1289ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_EHFC); 1290ba4dfef1SStephen Warren 1291ba4dfef1SStephen Warren /* 1292ba4dfef1SStephen Warren * Set Threshold for Activating Flow Contol space for min 2 1293ba4dfef1SStephen Warren * frames ie, (1500 * 1) = 1500 bytes. 1294ba4dfef1SStephen Warren * 1295ba4dfef1SStephen Warren * Set Threshold for Deactivating Flow Contol for space of 1296ba4dfef1SStephen Warren * min 1 frame (frame size 1500bytes) in receive fifo 1297ba4dfef1SStephen Warren */ 1298ba4dfef1SStephen Warren if (rqs == ((4096 / 256) - 1)) { 1299ba4dfef1SStephen Warren /* 1300ba4dfef1SStephen Warren * This violates the above formula because of FIFO size 1301ba4dfef1SStephen Warren * limit therefore overflow may occur inspite of this. 1302ba4dfef1SStephen Warren */ 1303ba4dfef1SStephen Warren rfd = 0x3; /* Full-3K */ 1304ba4dfef1SStephen Warren rfa = 0x1; /* Full-1.5K */ 1305ba4dfef1SStephen Warren } else if (rqs == ((8192 / 256) - 1)) { 1306ba4dfef1SStephen Warren rfd = 0x6; /* Full-4K */ 1307ba4dfef1SStephen Warren rfa = 0xa; /* Full-6K */ 1308ba4dfef1SStephen Warren } else if (rqs == ((16384 / 256) - 1)) { 1309ba4dfef1SStephen Warren rfd = 0x6; /* Full-4K */ 1310ba4dfef1SStephen Warren rfa = 0x12; /* Full-10K */ 1311ba4dfef1SStephen Warren } else { 1312ba4dfef1SStephen Warren rfd = 0x6; /* Full-4K */ 1313ba4dfef1SStephen Warren rfa = 0x1E; /* Full-16K */ 1314ba4dfef1SStephen Warren } 1315ba4dfef1SStephen Warren 1316ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1317ba4dfef1SStephen Warren (EQOS_MTL_RXQ0_OPERATION_MODE_RFD_MASK << 1318ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT) | 1319ba4dfef1SStephen Warren (EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK << 1320ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT), 1321ba4dfef1SStephen Warren (rfd << 1322ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT) | 1323ba4dfef1SStephen Warren (rfa << 1324ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT)); 1325ba4dfef1SStephen Warren } 1326ba4dfef1SStephen Warren 1327ba4dfef1SStephen Warren /* Configure MAC */ 1328ba4dfef1SStephen Warren 1329ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, 1330ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << 1331ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, 13327a4c4eddSChristophe Roullier eqos->config->config_mac << 1333ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); 1334ba4dfef1SStephen Warren 1335a7b3400fSFugang Duan clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, 1336a7b3400fSFugang Duan EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << 1337a7b3400fSFugang Duan EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, 1338a7b3400fSFugang Duan 0x2 << 1339a7b3400fSFugang Duan EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); 1340a7b3400fSFugang Duan 1341a7b3400fSFugang Duan /* Multicast and Broadcast Queue Enable */ 1342a7b3400fSFugang Duan setbits_le32(&eqos->mac_regs->unused_0a4, 1343a7b3400fSFugang Duan 0x00100000); 1344a7b3400fSFugang Duan /* enable promise mode */ 1345a7b3400fSFugang Duan setbits_le32(&eqos->mac_regs->unused_004[1], 1346a7b3400fSFugang Duan 0x1); 1347a7b3400fSFugang Duan 1348ba4dfef1SStephen Warren /* Set TX flow control parameters */ 1349ba4dfef1SStephen Warren /* Set Pause Time */ 1350ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl, 1351ba4dfef1SStephen Warren 0xffff << EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT); 1352ba4dfef1SStephen Warren /* Assign priority for TX flow control */ 1353ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->txq_prty_map0, 1354ba4dfef1SStephen Warren EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK << 1355ba4dfef1SStephen Warren EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_SHIFT); 1356ba4dfef1SStephen Warren /* Assign priority for RX flow control */ 1357ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->rxq_ctrl2, 1358ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK << 1359ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT); 1360ba4dfef1SStephen Warren /* Enable flow control */ 1361ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl, 1362ba4dfef1SStephen Warren EQOS_MAC_Q0_TX_FLOW_CTRL_TFE); 1363ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->rx_flow_ctrl, 1364ba4dfef1SStephen Warren EQOS_MAC_RX_FLOW_CTRL_RFE); 1365ba4dfef1SStephen Warren 1366ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mac_regs->configuration, 1367ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_GPSLCE | 1368ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_WD | 1369ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_JD | 1370ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_JE, 1371ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_CST | 1372ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_ACS); 1373ba4dfef1SStephen Warren 1374ba4dfef1SStephen Warren eqos_write_hwaddr(dev); 1375ba4dfef1SStephen Warren 1376ba4dfef1SStephen Warren /* Configure DMA */ 1377ba4dfef1SStephen Warren 1378ba4dfef1SStephen Warren /* Enable OSP mode */ 1379ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_tx_control, 1380ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_OSP); 1381ba4dfef1SStephen Warren 1382ba4dfef1SStephen Warren /* RX buffer size. Must be a multiple of bus width */ 1383ba4dfef1SStephen Warren clrsetbits_le32(&eqos->dma_regs->ch0_rx_control, 1384ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RBSZ_MASK << 1385ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT, 1386ba4dfef1SStephen Warren EQOS_MAX_PACKET_SIZE << 1387ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT); 1388ba4dfef1SStephen Warren 1389ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_control, 1390ba4dfef1SStephen Warren EQOS_DMA_CH0_CONTROL_PBLX8); 1391ba4dfef1SStephen Warren 1392ba4dfef1SStephen Warren /* 1393ba4dfef1SStephen Warren * Burst length must be < 1/2 FIFO size. 1394ba4dfef1SStephen Warren * FIFO size in tqs is encoded as (n / 256) - 1. 1395ba4dfef1SStephen Warren * Each burst is n * 8 (PBLX8) * 16 (AXI width) == 128 bytes. 1396ba4dfef1SStephen Warren * Half of n * 256 is n * 128, so pbl == tqs, modulo the -1. 1397ba4dfef1SStephen Warren */ 1398ba4dfef1SStephen Warren pbl = tqs + 1; 1399ba4dfef1SStephen Warren if (pbl > 32) 1400ba4dfef1SStephen Warren pbl = 32; 1401ba4dfef1SStephen Warren clrsetbits_le32(&eqos->dma_regs->ch0_tx_control, 1402ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_TXPBL_MASK << 1403ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT, 1404ba4dfef1SStephen Warren pbl << EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT); 1405ba4dfef1SStephen Warren 1406ba4dfef1SStephen Warren clrsetbits_le32(&eqos->dma_regs->ch0_rx_control, 1407ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RXPBL_MASK << 1408ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT, 1409ba4dfef1SStephen Warren 8 << EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT); 1410ba4dfef1SStephen Warren 1411ba4dfef1SStephen Warren /* DMA performance configuration */ 1412ba4dfef1SStephen Warren val = (2 << EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT) | 1413ba4dfef1SStephen Warren EQOS_DMA_SYSBUS_MODE_EAME | EQOS_DMA_SYSBUS_MODE_BLEN16 | 1414ba4dfef1SStephen Warren EQOS_DMA_SYSBUS_MODE_BLEN8 | EQOS_DMA_SYSBUS_MODE_BLEN4; 1415ba4dfef1SStephen Warren writel(val, &eqos->dma_regs->sysbus_mode); 1416ba4dfef1SStephen Warren 1417ba4dfef1SStephen Warren /* Set up descriptors */ 1418ba4dfef1SStephen Warren 1419ba4dfef1SStephen Warren memset(eqos->descs, 0, EQOS_DESCRIPTORS_SIZE); 1420ba4dfef1SStephen Warren for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) { 1421ba4dfef1SStephen Warren struct eqos_desc *rx_desc = &(eqos->rx_descs[i]); 1422ba4dfef1SStephen Warren rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + 1423ba4dfef1SStephen Warren (i * EQOS_MAX_PACKET_SIZE)); 14246143c348SMarek Vasut rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; 1425a7b3400fSFugang Duan mb(); 14266399c699SMarek Vasut eqos->config->ops->eqos_flush_desc(rx_desc); 1427a7b3400fSFugang Duan eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf + 1428a7b3400fSFugang Duan (i * EQOS_MAX_PACKET_SIZE), 1429a7b3400fSFugang Duan EQOS_MAX_PACKET_SIZE); 1430ba4dfef1SStephen Warren } 1431ba4dfef1SStephen Warren 1432ba4dfef1SStephen Warren writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); 1433ba4dfef1SStephen Warren writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address); 1434ba4dfef1SStephen Warren writel(EQOS_DESCRIPTORS_TX - 1, 1435ba4dfef1SStephen Warren &eqos->dma_regs->ch0_txdesc_ring_length); 1436ba4dfef1SStephen Warren 1437ba4dfef1SStephen Warren writel(0, &eqos->dma_regs->ch0_rxdesc_list_haddress); 1438ba4dfef1SStephen Warren writel((ulong)eqos->rx_descs, &eqos->dma_regs->ch0_rxdesc_list_address); 1439ba4dfef1SStephen Warren writel(EQOS_DESCRIPTORS_RX - 1, 1440ba4dfef1SStephen Warren &eqos->dma_regs->ch0_rxdesc_ring_length); 1441ba4dfef1SStephen Warren 1442ba4dfef1SStephen Warren /* Enable everything */ 1443ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_tx_control, 1444ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_ST); 1445ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_rx_control, 1446ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_SR); 1447a7b3400fSFugang Duan setbits_le32(&eqos->mac_regs->configuration, 1448a7b3400fSFugang Duan EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE); 1449ba4dfef1SStephen Warren 1450ba4dfef1SStephen Warren /* TX tail pointer not written until we need to TX a packet */ 1451ba4dfef1SStephen Warren /* 1452ba4dfef1SStephen Warren * Point RX tail pointer at last descriptor. Ideally, we'd point at the 1453ba4dfef1SStephen Warren * first descriptor, implying all descriptors were available. However, 1454ba4dfef1SStephen Warren * that's not distinguishable from none of the descriptors being 1455ba4dfef1SStephen Warren * available. 1456ba4dfef1SStephen Warren */ 1457ba4dfef1SStephen Warren last_rx_desc = (ulong)&(eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)]); 1458ba4dfef1SStephen Warren writel(last_rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); 1459ba4dfef1SStephen Warren 1460ba4dfef1SStephen Warren eqos->started = true; 14615bcea7aaSDavid Wu } 1462ba4dfef1SStephen Warren 14635bcea7aaSDavid Wu static int eqos_start(struct udevice *dev) 14645bcea7aaSDavid Wu { 14655bcea7aaSDavid Wu int ret; 1466ba4dfef1SStephen Warren 14675bcea7aaSDavid Wu ret = eqos_init(dev); 14685bcea7aaSDavid Wu if (ret) 1469ba4dfef1SStephen Warren return ret; 14705bcea7aaSDavid Wu 14715bcea7aaSDavid Wu eqos_enable(dev); 14725bcea7aaSDavid Wu 14735bcea7aaSDavid Wu return 0; 1474ba4dfef1SStephen Warren } 1475ba4dfef1SStephen Warren 147623ca6f74SDavid Wu void eqos_stop(struct udevice *dev) 1477ba4dfef1SStephen Warren { 1478ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1479ba4dfef1SStephen Warren int i; 1480ba4dfef1SStephen Warren 1481ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1482ba4dfef1SStephen Warren 1483ba4dfef1SStephen Warren if (!eqos->started) 1484ba4dfef1SStephen Warren return; 1485ba4dfef1SStephen Warren eqos->started = false; 1486ba4dfef1SStephen Warren eqos->reg_access_ok = false; 1487ba4dfef1SStephen Warren 1488ba4dfef1SStephen Warren /* Disable TX DMA */ 1489ba4dfef1SStephen Warren clrbits_le32(&eqos->dma_regs->ch0_tx_control, 1490ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_ST); 1491ba4dfef1SStephen Warren 1492ba4dfef1SStephen Warren /* Wait for TX all packets to drain out of MTL */ 1493ba4dfef1SStephen Warren for (i = 0; i < 1000000; i++) { 1494ba4dfef1SStephen Warren u32 val = readl(&eqos->mtl_regs->txq0_debug); 1495ba4dfef1SStephen Warren u32 trcsts = (val >> EQOS_MTL_TXQ0_DEBUG_TRCSTS_SHIFT) & 1496ba4dfef1SStephen Warren EQOS_MTL_TXQ0_DEBUG_TRCSTS_MASK; 1497ba4dfef1SStephen Warren u32 txqsts = val & EQOS_MTL_TXQ0_DEBUG_TXQSTS; 1498ba4dfef1SStephen Warren if ((trcsts != 1) && (!txqsts)) 1499ba4dfef1SStephen Warren break; 1500ba4dfef1SStephen Warren } 1501ba4dfef1SStephen Warren 1502ba4dfef1SStephen Warren /* Turn off MAC TX and RX */ 1503ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->configuration, 1504ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE); 1505ba4dfef1SStephen Warren 1506ba4dfef1SStephen Warren /* Wait for all RX packets to drain out of MTL */ 1507ba4dfef1SStephen Warren for (i = 0; i < 1000000; i++) { 1508ba4dfef1SStephen Warren u32 val = readl(&eqos->mtl_regs->rxq0_debug); 1509ba4dfef1SStephen Warren u32 prxq = (val >> EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT) & 1510ba4dfef1SStephen Warren EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK; 1511ba4dfef1SStephen Warren u32 rxqsts = (val >> EQOS_MTL_RXQ0_DEBUG_RXQSTS_SHIFT) & 1512ba4dfef1SStephen Warren EQOS_MTL_RXQ0_DEBUG_RXQSTS_MASK; 1513ba4dfef1SStephen Warren if ((!prxq) && (!rxqsts)) 1514ba4dfef1SStephen Warren break; 1515ba4dfef1SStephen Warren } 1516ba4dfef1SStephen Warren 1517ba4dfef1SStephen Warren /* Turn off RX DMA */ 1518ba4dfef1SStephen Warren clrbits_le32(&eqos->dma_regs->ch0_rx_control, 1519ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_SR); 1520ba4dfef1SStephen Warren 1521ba4dfef1SStephen Warren if (eqos->phy) { 1522ba4dfef1SStephen Warren phy_shutdown(eqos->phy); 1523ba4dfef1SStephen Warren } 15247a4c4eddSChristophe Roullier eqos->config->ops->eqos_stop_resets(dev); 1525e2d58431SDavid Wu if (eqos->config->ops->eqos_stop_clks) 15267a4c4eddSChristophe Roullier eqos->config->ops->eqos_stop_clks(dev); 1527ba4dfef1SStephen Warren 1528ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1529ba4dfef1SStephen Warren } 1530ba4dfef1SStephen Warren 153123ca6f74SDavid Wu int eqos_send(struct udevice *dev, void *packet, int length) 1532ba4dfef1SStephen Warren { 1533ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1534ba4dfef1SStephen Warren struct eqos_desc *tx_desc; 1535ba4dfef1SStephen Warren int i; 1536ba4dfef1SStephen Warren 1537ba4dfef1SStephen Warren debug("%s(dev=%p, packet=%p, length=%d):\n", __func__, dev, packet, 1538ba4dfef1SStephen Warren length); 1539ba4dfef1SStephen Warren 1540ba4dfef1SStephen Warren memcpy(eqos->tx_dma_buf, packet, length); 15417a4c4eddSChristophe Roullier eqos->config->ops->eqos_flush_buffer(eqos->tx_dma_buf, length); 1542ba4dfef1SStephen Warren 1543ba4dfef1SStephen Warren tx_desc = &(eqos->tx_descs[eqos->tx_desc_idx]); 1544ba4dfef1SStephen Warren eqos->tx_desc_idx++; 1545ba4dfef1SStephen Warren eqos->tx_desc_idx %= EQOS_DESCRIPTORS_TX; 1546ba4dfef1SStephen Warren 1547ba4dfef1SStephen Warren tx_desc->des0 = (ulong)eqos->tx_dma_buf; 1548ba4dfef1SStephen Warren tx_desc->des1 = 0; 1549ba4dfef1SStephen Warren tx_desc->des2 = length; 1550ba4dfef1SStephen Warren /* 1551ba4dfef1SStephen Warren * Make sure that if HW sees the _OWN write below, it will see all the 1552ba4dfef1SStephen Warren * writes to the rest of the descriptor too. 1553ba4dfef1SStephen Warren */ 1554ba4dfef1SStephen Warren mb(); 1555ba4dfef1SStephen Warren tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length; 15567a4c4eddSChristophe Roullier eqos->config->ops->eqos_flush_desc(tx_desc); 1557ba4dfef1SStephen Warren 1558364f8fdcSMarek Vasut writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])), 1559364f8fdcSMarek Vasut &eqos->dma_regs->ch0_txdesc_tail_pointer); 1560ba4dfef1SStephen Warren 1561ba4dfef1SStephen Warren for (i = 0; i < 1000000; i++) { 15627a4c4eddSChristophe Roullier eqos->config->ops->eqos_inval_desc(tx_desc); 1563ba4dfef1SStephen Warren if (!(readl(&tx_desc->des3) & EQOS_DESC3_OWN)) 1564ba4dfef1SStephen Warren return 0; 1565ba4dfef1SStephen Warren udelay(1); 1566ba4dfef1SStephen Warren } 1567ba4dfef1SStephen Warren 1568ba4dfef1SStephen Warren debug("%s: TX timeout\n", __func__); 1569ba4dfef1SStephen Warren 1570ba4dfef1SStephen Warren return -ETIMEDOUT; 1571ba4dfef1SStephen Warren } 1572ba4dfef1SStephen Warren 157323ca6f74SDavid Wu int eqos_recv(struct udevice *dev, int flags, uchar **packetp) 1574ba4dfef1SStephen Warren { 1575ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1576ba4dfef1SStephen Warren struct eqos_desc *rx_desc; 1577ba4dfef1SStephen Warren int length; 1578ba4dfef1SStephen Warren 1579ba4dfef1SStephen Warren debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags); 1580ba4dfef1SStephen Warren 1581ba4dfef1SStephen Warren rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); 1582865fce80SMarek Vasut eqos->config->ops->eqos_inval_desc(rx_desc); 1583ba4dfef1SStephen Warren if (rx_desc->des3 & EQOS_DESC3_OWN) { 1584ba4dfef1SStephen Warren debug("%s: RX packet not available\n", __func__); 1585ba4dfef1SStephen Warren return -EAGAIN; 1586ba4dfef1SStephen Warren } 1587ba4dfef1SStephen Warren 1588ba4dfef1SStephen Warren *packetp = eqos->rx_dma_buf + 1589ba4dfef1SStephen Warren (eqos->rx_desc_idx * EQOS_MAX_PACKET_SIZE); 1590ba4dfef1SStephen Warren length = rx_desc->des3 & 0x7fff; 1591ba4dfef1SStephen Warren debug("%s: *packetp=%p, length=%d\n", __func__, *packetp, length); 1592ba4dfef1SStephen Warren 15937a4c4eddSChristophe Roullier eqos->config->ops->eqos_inval_buffer(*packetp, length); 1594ba4dfef1SStephen Warren 1595ba4dfef1SStephen Warren return length; 1596ba4dfef1SStephen Warren } 1597ba4dfef1SStephen Warren 159823ca6f74SDavid Wu int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) 1599ba4dfef1SStephen Warren { 1600ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1601ba4dfef1SStephen Warren uchar *packet_expected; 1602ba4dfef1SStephen Warren struct eqos_desc *rx_desc; 1603ba4dfef1SStephen Warren 1604ba4dfef1SStephen Warren debug("%s(packet=%p, length=%d)\n", __func__, packet, length); 1605ba4dfef1SStephen Warren 1606ba4dfef1SStephen Warren packet_expected = eqos->rx_dma_buf + 1607ba4dfef1SStephen Warren (eqos->rx_desc_idx * EQOS_MAX_PACKET_SIZE); 1608ba4dfef1SStephen Warren if (packet != packet_expected) { 1609ba4dfef1SStephen Warren debug("%s: Unexpected packet (expected %p)\n", __func__, 1610ba4dfef1SStephen Warren packet_expected); 1611ba4dfef1SStephen Warren return -EINVAL; 1612ba4dfef1SStephen Warren } 1613ba4dfef1SStephen Warren 1614a7b3400fSFugang Duan eqos->config->ops->eqos_inval_buffer(packet, length); 1615a7b3400fSFugang Duan 1616ba4dfef1SStephen Warren rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); 1617076e66fbSMarek Vasut 161807314278SMarek Vasut rx_desc->des0 = 0; 161907314278SMarek Vasut mb(); 162007314278SMarek Vasut eqos->config->ops->eqos_flush_desc(rx_desc); 1621076e66fbSMarek Vasut eqos->config->ops->eqos_inval_buffer(packet, length); 1622ba4dfef1SStephen Warren rx_desc->des0 = (u32)(ulong)packet; 1623ba4dfef1SStephen Warren rx_desc->des1 = 0; 1624ba4dfef1SStephen Warren rx_desc->des2 = 0; 1625ba4dfef1SStephen Warren /* 1626ba4dfef1SStephen Warren * Make sure that if HW sees the _OWN write below, it will see all the 1627ba4dfef1SStephen Warren * writes to the rest of the descriptor too. 1628ba4dfef1SStephen Warren */ 1629ba4dfef1SStephen Warren mb(); 16306143c348SMarek Vasut rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; 16317a4c4eddSChristophe Roullier eqos->config->ops->eqos_flush_desc(rx_desc); 1632ba4dfef1SStephen Warren 1633ba4dfef1SStephen Warren writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); 1634ba4dfef1SStephen Warren 1635ba4dfef1SStephen Warren eqos->rx_desc_idx++; 1636ba4dfef1SStephen Warren eqos->rx_desc_idx %= EQOS_DESCRIPTORS_RX; 1637ba4dfef1SStephen Warren 1638ba4dfef1SStephen Warren return 0; 1639ba4dfef1SStephen Warren } 1640ba4dfef1SStephen Warren 1641ba4dfef1SStephen Warren static int eqos_probe_resources_core(struct udevice *dev) 1642ba4dfef1SStephen Warren { 1643ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1644ba4dfef1SStephen Warren int ret; 1645ba4dfef1SStephen Warren 1646ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1647ba4dfef1SStephen Warren 1648ba4dfef1SStephen Warren eqos->descs = eqos_alloc_descs(EQOS_DESCRIPTORS_TX + 1649ba4dfef1SStephen Warren EQOS_DESCRIPTORS_RX); 1650ba4dfef1SStephen Warren if (!eqos->descs) { 1651ba4dfef1SStephen Warren debug("%s: eqos_alloc_descs() failed\n", __func__); 1652ba4dfef1SStephen Warren ret = -ENOMEM; 1653ba4dfef1SStephen Warren goto err; 1654ba4dfef1SStephen Warren } 1655ba4dfef1SStephen Warren eqos->tx_descs = (struct eqos_desc *)eqos->descs; 1656ba4dfef1SStephen Warren eqos->rx_descs = (eqos->tx_descs + EQOS_DESCRIPTORS_TX); 1657ba4dfef1SStephen Warren debug("%s: tx_descs=%p, rx_descs=%p\n", __func__, eqos->tx_descs, 1658ba4dfef1SStephen Warren eqos->rx_descs); 1659ba4dfef1SStephen Warren 1660ba4dfef1SStephen Warren eqos->tx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_MAX_PACKET_SIZE); 1661ba4dfef1SStephen Warren if (!eqos->tx_dma_buf) { 1662ba4dfef1SStephen Warren debug("%s: memalign(tx_dma_buf) failed\n", __func__); 1663ba4dfef1SStephen Warren ret = -ENOMEM; 1664ba4dfef1SStephen Warren goto err_free_descs; 1665ba4dfef1SStephen Warren } 16667a4c4eddSChristophe Roullier debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); 1667ba4dfef1SStephen Warren 1668ba4dfef1SStephen Warren eqos->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_RX_BUFFER_SIZE); 1669ba4dfef1SStephen Warren if (!eqos->rx_dma_buf) { 1670ba4dfef1SStephen Warren debug("%s: memalign(rx_dma_buf) failed\n", __func__); 1671ba4dfef1SStephen Warren ret = -ENOMEM; 1672ba4dfef1SStephen Warren goto err_free_tx_dma_buf; 1673ba4dfef1SStephen Warren } 16747a4c4eddSChristophe Roullier debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); 1675ba4dfef1SStephen Warren 1676ba4dfef1SStephen Warren eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE); 1677ba4dfef1SStephen Warren if (!eqos->rx_pkt) { 1678ba4dfef1SStephen Warren debug("%s: malloc(rx_pkt) failed\n", __func__); 1679ba4dfef1SStephen Warren ret = -ENOMEM; 1680ba4dfef1SStephen Warren goto err_free_rx_dma_buf; 1681ba4dfef1SStephen Warren } 1682ba4dfef1SStephen Warren debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt); 1683ba4dfef1SStephen Warren 1684076e66fbSMarek Vasut eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf, 1685076e66fbSMarek Vasut EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX); 1686076e66fbSMarek Vasut 1687ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1688ba4dfef1SStephen Warren return 0; 1689ba4dfef1SStephen Warren 1690ba4dfef1SStephen Warren err_free_rx_dma_buf: 1691ba4dfef1SStephen Warren free(eqos->rx_dma_buf); 1692ba4dfef1SStephen Warren err_free_tx_dma_buf: 1693ba4dfef1SStephen Warren free(eqos->tx_dma_buf); 1694ba4dfef1SStephen Warren err_free_descs: 1695ba4dfef1SStephen Warren eqos_free_descs(eqos->descs); 1696ba4dfef1SStephen Warren err: 1697ba4dfef1SStephen Warren 1698ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 1699ba4dfef1SStephen Warren return ret; 1700ba4dfef1SStephen Warren } 1701ba4dfef1SStephen Warren 1702ba4dfef1SStephen Warren static int eqos_remove_resources_core(struct udevice *dev) 1703ba4dfef1SStephen Warren { 1704ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1705ba4dfef1SStephen Warren 1706ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1707ba4dfef1SStephen Warren 1708ba4dfef1SStephen Warren free(eqos->rx_pkt); 1709ba4dfef1SStephen Warren free(eqos->rx_dma_buf); 1710ba4dfef1SStephen Warren free(eqos->tx_dma_buf); 1711ba4dfef1SStephen Warren eqos_free_descs(eqos->descs); 1712ba4dfef1SStephen Warren 1713ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1714ba4dfef1SStephen Warren return 0; 1715ba4dfef1SStephen Warren } 1716ba4dfef1SStephen Warren 1717ba4dfef1SStephen Warren static int eqos_probe_resources_tegra186(struct udevice *dev) 1718ba4dfef1SStephen Warren { 1719ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1720ba4dfef1SStephen Warren int ret; 1721ba4dfef1SStephen Warren 1722ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1723ba4dfef1SStephen Warren 1724ba4dfef1SStephen Warren ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl); 1725ba4dfef1SStephen Warren if (ret) { 172690aa625cSMasahiro Yamada pr_err("reset_get_by_name(rst) failed: %d", ret); 1727ba4dfef1SStephen Warren return ret; 1728ba4dfef1SStephen Warren } 1729ba4dfef1SStephen Warren 1730ba4dfef1SStephen Warren ret = gpio_request_by_name(dev, "phy-reset-gpios", 0, 1731ba4dfef1SStephen Warren &eqos->phy_reset_gpio, 1732ba4dfef1SStephen Warren GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 1733ba4dfef1SStephen Warren if (ret) { 173490aa625cSMasahiro Yamada pr_err("gpio_request_by_name(phy reset) failed: %d", ret); 1735ba4dfef1SStephen Warren goto err_free_reset_eqos; 1736ba4dfef1SStephen Warren } 1737ba4dfef1SStephen Warren 1738ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "slave_bus", &eqos->clk_slave_bus); 1739ba4dfef1SStephen Warren if (ret) { 174090aa625cSMasahiro Yamada pr_err("clk_get_by_name(slave_bus) failed: %d", ret); 1741ba4dfef1SStephen Warren goto err_free_gpio_phy_reset; 1742ba4dfef1SStephen Warren } 1743ba4dfef1SStephen Warren 1744ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "master_bus", &eqos->clk_master_bus); 1745ba4dfef1SStephen Warren if (ret) { 174690aa625cSMasahiro Yamada pr_err("clk_get_by_name(master_bus) failed: %d", ret); 1747ba4dfef1SStephen Warren goto err_free_clk_slave_bus; 1748ba4dfef1SStephen Warren } 1749ba4dfef1SStephen Warren 1750ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "rx", &eqos->clk_rx); 1751ba4dfef1SStephen Warren if (ret) { 175290aa625cSMasahiro Yamada pr_err("clk_get_by_name(rx) failed: %d", ret); 1753ba4dfef1SStephen Warren goto err_free_clk_master_bus; 1754ba4dfef1SStephen Warren } 1755ba4dfef1SStephen Warren 1756ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); 1757ba4dfef1SStephen Warren if (ret) { 175890aa625cSMasahiro Yamada pr_err("clk_get_by_name(ptp_ref) failed: %d", ret); 1759ba4dfef1SStephen Warren goto err_free_clk_rx; 1760ba4dfef1SStephen Warren return ret; 1761ba4dfef1SStephen Warren } 1762ba4dfef1SStephen Warren 1763ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "tx", &eqos->clk_tx); 1764ba4dfef1SStephen Warren if (ret) { 176590aa625cSMasahiro Yamada pr_err("clk_get_by_name(tx) failed: %d", ret); 1766ba4dfef1SStephen Warren goto err_free_clk_ptp_ref; 1767ba4dfef1SStephen Warren } 1768ba4dfef1SStephen Warren 1769ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1770ba4dfef1SStephen Warren return 0; 1771ba4dfef1SStephen Warren 1772ba4dfef1SStephen Warren err_free_clk_ptp_ref: 1773ba4dfef1SStephen Warren clk_free(&eqos->clk_ptp_ref); 1774ba4dfef1SStephen Warren err_free_clk_rx: 1775ba4dfef1SStephen Warren clk_free(&eqos->clk_rx); 1776ba4dfef1SStephen Warren err_free_clk_master_bus: 1777ba4dfef1SStephen Warren clk_free(&eqos->clk_master_bus); 1778ba4dfef1SStephen Warren err_free_clk_slave_bus: 1779ba4dfef1SStephen Warren clk_free(&eqos->clk_slave_bus); 1780ba4dfef1SStephen Warren err_free_gpio_phy_reset: 1781ba4dfef1SStephen Warren dm_gpio_free(dev, &eqos->phy_reset_gpio); 1782ba4dfef1SStephen Warren err_free_reset_eqos: 1783ba4dfef1SStephen Warren reset_free(&eqos->reset_ctl); 1784ba4dfef1SStephen Warren 1785ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 1786ba4dfef1SStephen Warren return ret; 1787ba4dfef1SStephen Warren } 1788ba4dfef1SStephen Warren 17897a4c4eddSChristophe Roullier /* board-specific Ethernet Interface initializations. */ 17901e8d5d80SPatrick Delaunay __weak int board_interface_eth_init(struct udevice *dev, 17911e8d5d80SPatrick Delaunay phy_interface_t interface_type) 17927a4c4eddSChristophe Roullier { 17937a4c4eddSChristophe Roullier return 0; 17947a4c4eddSChristophe Roullier } 17957a4c4eddSChristophe Roullier 17967a4c4eddSChristophe Roullier static int eqos_probe_resources_stm32(struct udevice *dev) 17977a4c4eddSChristophe Roullier { 17987a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 17997a4c4eddSChristophe Roullier int ret; 18007a4c4eddSChristophe Roullier phy_interface_t interface; 18015bd3c538SChristophe Roullier struct ofnode_phandle_args phandle_args; 18027a4c4eddSChristophe Roullier 18037a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 18047a4c4eddSChristophe Roullier 1805bbbbc81cSDavid Wu interface = eqos->config->ops->eqos_get_interface(dev); 18067a4c4eddSChristophe Roullier 18077a4c4eddSChristophe Roullier if (interface == PHY_INTERFACE_MODE_NONE) { 18087a4c4eddSChristophe Roullier pr_err("Invalid PHY interface\n"); 18097a4c4eddSChristophe Roullier return -EINVAL; 18107a4c4eddSChristophe Roullier } 18117a4c4eddSChristophe Roullier 18121e8d5d80SPatrick Delaunay ret = board_interface_eth_init(dev, interface); 18137a4c4eddSChristophe Roullier if (ret) 18147a4c4eddSChristophe Roullier return -EINVAL; 18157a4c4eddSChristophe Roullier 181683d31c08SPatrick Delaunay eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); 181783d31c08SPatrick Delaunay 18187a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); 18197a4c4eddSChristophe Roullier if (ret) { 18207a4c4eddSChristophe Roullier pr_err("clk_get_by_name(master_bus) failed: %d", ret); 1821b29cefabSDavid Wu return ret; 18227a4c4eddSChristophe Roullier } 18237a4c4eddSChristophe Roullier 18247a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx); 1825b29cefabSDavid Wu if (ret) 1826b29cefabSDavid Wu pr_warn("clk_get_by_name(rx) failed: %d", ret); 18277a4c4eddSChristophe Roullier 18287a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx); 1829b29cefabSDavid Wu if (ret) 1830b29cefabSDavid Wu pr_warn("clk_get_by_name(tx) failed: %d", ret); 18317a4c4eddSChristophe Roullier 18327a4c4eddSChristophe Roullier /* Get ETH_CLK clocks (optional) */ 18337a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck); 18347a4c4eddSChristophe Roullier if (ret) 18357a4c4eddSChristophe Roullier pr_warn("No phy clock provided %d", ret); 18367a4c4eddSChristophe Roullier 183783d31c08SPatrick Delaunay eqos->phyaddr = -1; 18385bd3c538SChristophe Roullier ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, 18395bd3c538SChristophe Roullier &phandle_args); 18405bd3c538SChristophe Roullier if (!ret) { 18415bd3c538SChristophe Roullier /* search "reset-gpios" in phy node */ 18425bd3c538SChristophe Roullier ret = gpio_request_by_name_nodev(phandle_args.node, 18435bd3c538SChristophe Roullier "reset-gpios", 0, 18445bd3c538SChristophe Roullier &eqos->phy_reset_gpio, 18455bd3c538SChristophe Roullier GPIOD_IS_OUT | 18465bd3c538SChristophe Roullier GPIOD_IS_OUT_ACTIVE); 18475bd3c538SChristophe Roullier if (ret) 18485bd3c538SChristophe Roullier pr_warn("gpio_request_by_name(phy reset) not provided %d", 18495bd3c538SChristophe Roullier ret); 185013105a0bSDavid Wu else 185113105a0bSDavid Wu eqos->reset_delays[1] = 2; 185283d31c08SPatrick Delaunay 185383d31c08SPatrick Delaunay eqos->phyaddr = ofnode_read_u32_default(phandle_args.node, 185483d31c08SPatrick Delaunay "reg", -1); 18555bd3c538SChristophe Roullier } 18565bd3c538SChristophe Roullier 185713105a0bSDavid Wu if (!dm_gpio_is_valid(&eqos->phy_reset_gpio)) { 185813105a0bSDavid Wu int reset_flags = GPIOD_IS_OUT; 185913105a0bSDavid Wu 186013105a0bSDavid Wu if (dev_read_bool(dev, "snps,reset-active-low")) 186113105a0bSDavid Wu reset_flags |= GPIOD_ACTIVE_LOW; 186213105a0bSDavid Wu 186313105a0bSDavid Wu ret = gpio_request_by_name(dev, "snps,reset-gpio", 0, 186413105a0bSDavid Wu &eqos->phy_reset_gpio, reset_flags); 186513105a0bSDavid Wu if (ret == 0) 186613105a0bSDavid Wu ret = dev_read_u32_array(dev, "snps,reset-delays-us", 186713105a0bSDavid Wu eqos->reset_delays, 3); 186813105a0bSDavid Wu else 186913105a0bSDavid Wu pr_warn("gpio_request_by_name(snps,reset-gpio) failed: %d", 187013105a0bSDavid Wu ret); 187113105a0bSDavid Wu } 187213105a0bSDavid Wu 18737a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 18747a4c4eddSChristophe Roullier return 0; 18757a4c4eddSChristophe Roullier } 18767a4c4eddSChristophe Roullier 18777a4c4eddSChristophe Roullier static phy_interface_t eqos_get_interface_stm32(struct udevice *dev) 18787a4c4eddSChristophe Roullier { 18797a4c4eddSChristophe Roullier const char *phy_mode; 18807a4c4eddSChristophe Roullier phy_interface_t interface = PHY_INTERFACE_MODE_NONE; 18817a4c4eddSChristophe Roullier 18827a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 18837a4c4eddSChristophe Roullier 1884dcf8de12SDavid Wu phy_mode = dev_read_string(dev, "phy-mode"); 18857a4c4eddSChristophe Roullier if (phy_mode) 18867a4c4eddSChristophe Roullier interface = phy_get_interface_by_name(phy_mode); 18877a4c4eddSChristophe Roullier 18887a4c4eddSChristophe Roullier return interface; 18897a4c4eddSChristophe Roullier } 18907a4c4eddSChristophe Roullier 18917a4c4eddSChristophe Roullier static phy_interface_t eqos_get_interface_tegra186(struct udevice *dev) 18927a4c4eddSChristophe Roullier { 18937a4c4eddSChristophe Roullier return PHY_INTERFACE_MODE_MII; 18947a4c4eddSChristophe Roullier } 18957a4c4eddSChristophe Roullier 1896a7b3400fSFugang Duan static int eqos_probe_resources_imx(struct udevice *dev) 1897a7b3400fSFugang Duan { 1898a7b3400fSFugang Duan struct eqos_priv *eqos = dev_get_priv(dev); 1899a7b3400fSFugang Duan phy_interface_t interface; 1900a7b3400fSFugang Duan 1901a7b3400fSFugang Duan debug("%s(dev=%p):\n", __func__, dev); 1902a7b3400fSFugang Duan 1903bbbbc81cSDavid Wu interface = eqos->config->ops->eqos_get_interface(dev); 1904a7b3400fSFugang Duan 1905a7b3400fSFugang Duan if (interface == PHY_INTERFACE_MODE_NONE) { 1906a7b3400fSFugang Duan pr_err("Invalid PHY interface\n"); 1907a7b3400fSFugang Duan return -EINVAL; 1908a7b3400fSFugang Duan } 1909a7b3400fSFugang Duan 1910a7b3400fSFugang Duan debug("%s: OK\n", __func__); 1911a7b3400fSFugang Duan return 0; 1912a7b3400fSFugang Duan } 1913a7b3400fSFugang Duan 1914a7b3400fSFugang Duan static phy_interface_t eqos_get_interface_imx(struct udevice *dev) 1915a7b3400fSFugang Duan { 1916ad018a0cSFugang Duan const char *phy_mode; 1917ad018a0cSFugang Duan phy_interface_t interface = PHY_INTERFACE_MODE_NONE; 1918ad018a0cSFugang Duan 1919ad018a0cSFugang Duan debug("%s(dev=%p):\n", __func__, dev); 1920ad018a0cSFugang Duan 1921ad018a0cSFugang Duan phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", 1922ad018a0cSFugang Duan NULL); 1923ad018a0cSFugang Duan if (phy_mode) 1924ad018a0cSFugang Duan interface = phy_get_interface_by_name(phy_mode); 1925ad018a0cSFugang Duan 1926ad018a0cSFugang Duan return interface; 1927a7b3400fSFugang Duan } 1928a7b3400fSFugang Duan 1929ba4dfef1SStephen Warren static int eqos_remove_resources_tegra186(struct udevice *dev) 1930ba4dfef1SStephen Warren { 1931ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1932ba4dfef1SStephen Warren 1933ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1934ba4dfef1SStephen Warren 1935a7b3400fSFugang Duan #ifdef CONFIG_CLK 1936ba4dfef1SStephen Warren clk_free(&eqos->clk_tx); 1937ba4dfef1SStephen Warren clk_free(&eqos->clk_ptp_ref); 1938ba4dfef1SStephen Warren clk_free(&eqos->clk_rx); 1939ba4dfef1SStephen Warren clk_free(&eqos->clk_slave_bus); 1940ba4dfef1SStephen Warren clk_free(&eqos->clk_master_bus); 1941a7b3400fSFugang Duan #endif 1942ba4dfef1SStephen Warren dm_gpio_free(dev, &eqos->phy_reset_gpio); 1943ba4dfef1SStephen Warren reset_free(&eqos->reset_ctl); 1944ba4dfef1SStephen Warren 1945ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1946ba4dfef1SStephen Warren return 0; 1947ba4dfef1SStephen Warren } 1948ba4dfef1SStephen Warren 19497a4c4eddSChristophe Roullier static int eqos_remove_resources_stm32(struct udevice *dev) 19507a4c4eddSChristophe Roullier { 1951a7b3400fSFugang Duan #ifdef CONFIG_CLK 19527a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 19537a4c4eddSChristophe Roullier 19547a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 19557a4c4eddSChristophe Roullier 1956b29cefabSDavid Wu if (clk_valid(&eqos->clk_tx)) 19577a4c4eddSChristophe Roullier clk_free(&eqos->clk_tx); 1958b29cefabSDavid Wu if (clk_valid(&eqos->clk_rx)) 19597a4c4eddSChristophe Roullier clk_free(&eqos->clk_rx); 19607a4c4eddSChristophe Roullier clk_free(&eqos->clk_master_bus); 19617a4c4eddSChristophe Roullier if (clk_valid(&eqos->clk_ck)) 19627a4c4eddSChristophe Roullier clk_free(&eqos->clk_ck); 1963a7b3400fSFugang Duan #endif 19647a4c4eddSChristophe Roullier 19655bd3c538SChristophe Roullier if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) 19665bd3c538SChristophe Roullier dm_gpio_free(dev, &eqos->phy_reset_gpio); 19675bd3c538SChristophe Roullier 19687a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 19697a4c4eddSChristophe Roullier return 0; 19707a4c4eddSChristophe Roullier } 19717a4c4eddSChristophe Roullier 1972a7b3400fSFugang Duan static int eqos_remove_resources_imx(struct udevice *dev) 1973a7b3400fSFugang Duan { 1974a7b3400fSFugang Duan return 0; 1975a7b3400fSFugang Duan } 1976a7b3400fSFugang Duan 197723ca6f74SDavid Wu int eqos_probe(struct udevice *dev) 1978ba4dfef1SStephen Warren { 1979ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1980ba4dfef1SStephen Warren int ret; 1981ba4dfef1SStephen Warren 1982ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1983ba4dfef1SStephen Warren 1984ba4dfef1SStephen Warren eqos->dev = dev; 1985ba4dfef1SStephen Warren eqos->config = (void *)dev_get_driver_data(dev); 1986ba4dfef1SStephen Warren 1987dcf8de12SDavid Wu eqos->regs = dev_read_addr(dev); 1988ba4dfef1SStephen Warren if (eqos->regs == FDT_ADDR_T_NONE) { 1989dcf8de12SDavid Wu pr_err("dev_read_addr() failed"); 1990ba4dfef1SStephen Warren return -ENODEV; 1991ba4dfef1SStephen Warren } 1992ba4dfef1SStephen Warren eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE); 1993ba4dfef1SStephen Warren eqos->mtl_regs = (void *)(eqos->regs + EQOS_MTL_REGS_BASE); 1994ba4dfef1SStephen Warren eqos->dma_regs = (void *)(eqos->regs + EQOS_DMA_REGS_BASE); 1995ba4dfef1SStephen Warren eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE); 1996ba4dfef1SStephen Warren 1997ba4dfef1SStephen Warren ret = eqos_probe_resources_core(dev); 1998ba4dfef1SStephen Warren if (ret < 0) { 199990aa625cSMasahiro Yamada pr_err("eqos_probe_resources_core() failed: %d", ret); 2000ba4dfef1SStephen Warren return ret; 2001ba4dfef1SStephen Warren } 2002ba4dfef1SStephen Warren 20037a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_probe_resources(dev); 2004ba4dfef1SStephen Warren if (ret < 0) { 20057a4c4eddSChristophe Roullier pr_err("eqos_probe_resources() failed: %d", ret); 2006ba4dfef1SStephen Warren goto err_remove_resources_core; 2007ba4dfef1SStephen Warren } 2008ba4dfef1SStephen Warren 20098e3eceb0SYe Li #ifdef CONFIG_DM_ETH_PHY 20108e3eceb0SYe Li eqos->mii = eth_phy_get_mdio_bus(dev); 20118e3eceb0SYe Li #endif 20128e3eceb0SYe Li if (!eqos->mii) { 2013ba4dfef1SStephen Warren eqos->mii = mdio_alloc(); 2014ba4dfef1SStephen Warren if (!eqos->mii) { 201590aa625cSMasahiro Yamada pr_err("mdio_alloc() failed"); 20167a4c4eddSChristophe Roullier ret = -ENOMEM; 2017ba4dfef1SStephen Warren goto err_remove_resources_tegra; 2018ba4dfef1SStephen Warren } 2019ba4dfef1SStephen Warren eqos->mii->read = eqos_mdio_read; 2020ba4dfef1SStephen Warren eqos->mii->write = eqos_mdio_write; 2021ba4dfef1SStephen Warren eqos->mii->priv = eqos; 2022ba4dfef1SStephen Warren strcpy(eqos->mii->name, dev->name); 2023ba4dfef1SStephen Warren 2024ba4dfef1SStephen Warren ret = mdio_register(eqos->mii); 2025ba4dfef1SStephen Warren if (ret < 0) { 202690aa625cSMasahiro Yamada pr_err("mdio_register() failed: %d", ret); 2027ba4dfef1SStephen Warren goto err_free_mdio; 2028ba4dfef1SStephen Warren } 20298e3eceb0SYe Li } 20308e3eceb0SYe Li 20318e3eceb0SYe Li #ifdef CONFIG_DM_ETH_PHY 20328e3eceb0SYe Li eth_phy_set_mdio_bus(dev, eqos->mii); 20338e3eceb0SYe Li #endif 2034ba4dfef1SStephen Warren 2035ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 2036ba4dfef1SStephen Warren return 0; 2037ba4dfef1SStephen Warren 2038ba4dfef1SStephen Warren err_free_mdio: 2039ba4dfef1SStephen Warren mdio_free(eqos->mii); 2040ba4dfef1SStephen Warren err_remove_resources_tegra: 20417a4c4eddSChristophe Roullier eqos->config->ops->eqos_remove_resources(dev); 2042ba4dfef1SStephen Warren err_remove_resources_core: 2043ba4dfef1SStephen Warren eqos_remove_resources_core(dev); 2044ba4dfef1SStephen Warren 2045ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 2046ba4dfef1SStephen Warren return ret; 2047ba4dfef1SStephen Warren } 2048ba4dfef1SStephen Warren 2049ba4dfef1SStephen Warren static int eqos_remove(struct udevice *dev) 2050ba4dfef1SStephen Warren { 2051ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 2052ba4dfef1SStephen Warren 2053ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 2054ba4dfef1SStephen Warren 2055ba4dfef1SStephen Warren mdio_unregister(eqos->mii); 2056ba4dfef1SStephen Warren mdio_free(eqos->mii); 20577a4c4eddSChristophe Roullier eqos->config->ops->eqos_remove_resources(dev); 20587a4c4eddSChristophe Roullier 2059ba4dfef1SStephen Warren eqos_probe_resources_core(dev); 2060ba4dfef1SStephen Warren 2061ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 2062ba4dfef1SStephen Warren return 0; 2063ba4dfef1SStephen Warren } 2064ba4dfef1SStephen Warren 2065ba4dfef1SStephen Warren static const struct eth_ops eqos_ops = { 2066ba4dfef1SStephen Warren .start = eqos_start, 2067ba4dfef1SStephen Warren .stop = eqos_stop, 2068ba4dfef1SStephen Warren .send = eqos_send, 2069ba4dfef1SStephen Warren .recv = eqos_recv, 2070ba4dfef1SStephen Warren .free_pkt = eqos_free_pkt, 2071ba4dfef1SStephen Warren .write_hwaddr = eqos_write_hwaddr, 20724d0fb6f0SYe Li .read_rom_hwaddr = eqos_read_rom_hwaddr, 2073ba4dfef1SStephen Warren }; 2074ba4dfef1SStephen Warren 20757a4c4eddSChristophe Roullier static struct eqos_ops eqos_tegra186_ops = { 20767a4c4eddSChristophe Roullier .eqos_inval_desc = eqos_inval_desc_tegra186, 20777a4c4eddSChristophe Roullier .eqos_flush_desc = eqos_flush_desc_tegra186, 20787a4c4eddSChristophe Roullier .eqos_inval_buffer = eqos_inval_buffer_tegra186, 20797a4c4eddSChristophe Roullier .eqos_flush_buffer = eqos_flush_buffer_tegra186, 20807a4c4eddSChristophe Roullier .eqos_probe_resources = eqos_probe_resources_tegra186, 20817a4c4eddSChristophe Roullier .eqos_remove_resources = eqos_remove_resources_tegra186, 20827a4c4eddSChristophe Roullier .eqos_stop_resets = eqos_stop_resets_tegra186, 20837a4c4eddSChristophe Roullier .eqos_start_resets = eqos_start_resets_tegra186, 20847a4c4eddSChristophe Roullier .eqos_stop_clks = eqos_stop_clks_tegra186, 20857a4c4eddSChristophe Roullier .eqos_start_clks = eqos_start_clks_tegra186, 20867a4c4eddSChristophe Roullier .eqos_calibrate_pads = eqos_calibrate_pads_tegra186, 20877a4c4eddSChristophe Roullier .eqos_disable_calibration = eqos_disable_calibration_tegra186, 20887a4c4eddSChristophe Roullier .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186, 2089bbbbc81cSDavid Wu .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186, 2090bbbbc81cSDavid Wu .eqos_get_interface = eqos_get_interface_tegra186 20917a4c4eddSChristophe Roullier }; 20927a4c4eddSChristophe Roullier 2093ba4dfef1SStephen Warren static const struct eqos_config eqos_tegra186_config = { 2094ba4dfef1SStephen Warren .reg_access_always_ok = false, 20957a4c4eddSChristophe Roullier .mdio_wait = 10, 20967a4c4eddSChristophe Roullier .swr_wait = 10, 20977a4c4eddSChristophe Roullier .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, 20987a4c4eddSChristophe Roullier .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, 20997a4c4eddSChristophe Roullier .ops = &eqos_tegra186_ops 21007a4c4eddSChristophe Roullier }; 21017a4c4eddSChristophe Roullier 21027a4c4eddSChristophe Roullier static struct eqos_ops eqos_stm32_ops = { 2103a7b3400fSFugang Duan .eqos_inval_desc = eqos_inval_desc_generic, 2104a7b3400fSFugang Duan .eqos_flush_desc = eqos_flush_desc_generic, 2105a7b3400fSFugang Duan .eqos_inval_buffer = eqos_inval_buffer_generic, 2106a7b3400fSFugang Duan .eqos_flush_buffer = eqos_flush_buffer_generic, 21077a4c4eddSChristophe Roullier .eqos_probe_resources = eqos_probe_resources_stm32, 21087a4c4eddSChristophe Roullier .eqos_remove_resources = eqos_remove_resources_stm32, 21097a4c4eddSChristophe Roullier .eqos_stop_resets = eqos_stop_resets_stm32, 21107a4c4eddSChristophe Roullier .eqos_start_resets = eqos_start_resets_stm32, 21117a4c4eddSChristophe Roullier .eqos_stop_clks = eqos_stop_clks_stm32, 21127a4c4eddSChristophe Roullier .eqos_start_clks = eqos_start_clks_stm32, 21137a4c4eddSChristophe Roullier .eqos_calibrate_pads = eqos_calibrate_pads_stm32, 21147a4c4eddSChristophe Roullier .eqos_disable_calibration = eqos_disable_calibration_stm32, 21157a4c4eddSChristophe Roullier .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32, 2116bbbbc81cSDavid Wu .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32, 2117bbbbc81cSDavid Wu .eqos_get_interface = eqos_get_interface_stm32 21187a4c4eddSChristophe Roullier }; 21197a4c4eddSChristophe Roullier 21207a4c4eddSChristophe Roullier static const struct eqos_config eqos_stm32_config = { 21217a4c4eddSChristophe Roullier .reg_access_always_ok = false, 21227a4c4eddSChristophe Roullier .mdio_wait = 10000, 21237a4c4eddSChristophe Roullier .swr_wait = 50, 21247a4c4eddSChristophe Roullier .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, 21257a4c4eddSChristophe Roullier .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, 21267a4c4eddSChristophe Roullier .ops = &eqos_stm32_ops 2127ba4dfef1SStephen Warren }; 2128ba4dfef1SStephen Warren 2129a7b3400fSFugang Duan static struct eqos_ops eqos_imx_ops = { 2130a7b3400fSFugang Duan .eqos_inval_desc = eqos_inval_desc_generic, 2131a7b3400fSFugang Duan .eqos_flush_desc = eqos_flush_desc_generic, 2132a7b3400fSFugang Duan .eqos_inval_buffer = eqos_inval_buffer_generic, 2133a7b3400fSFugang Duan .eqos_flush_buffer = eqos_flush_buffer_generic, 2134a7b3400fSFugang Duan .eqos_probe_resources = eqos_probe_resources_imx, 2135a7b3400fSFugang Duan .eqos_remove_resources = eqos_remove_resources_imx, 2136a7b3400fSFugang Duan .eqos_stop_resets = eqos_stop_resets_imx, 2137a7b3400fSFugang Duan .eqos_start_resets = eqos_start_resets_imx, 2138a7b3400fSFugang Duan .eqos_stop_clks = eqos_stop_clks_imx, 2139a7b3400fSFugang Duan .eqos_start_clks = eqos_start_clks_imx, 2140a7b3400fSFugang Duan .eqos_calibrate_pads = eqos_calibrate_pads_imx, 2141a7b3400fSFugang Duan .eqos_disable_calibration = eqos_disable_calibration_imx, 2142a7b3400fSFugang Duan .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_imx, 2143bbbbc81cSDavid Wu .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_imx, 2144bbbbc81cSDavid Wu .eqos_get_interface = eqos_get_interface_imx 2145a7b3400fSFugang Duan }; 2146a7b3400fSFugang Duan 2147a7b3400fSFugang Duan struct eqos_config eqos_imx_config = { 2148a7b3400fSFugang Duan .reg_access_always_ok = false, 2149a7b3400fSFugang Duan .mdio_wait = 10000, 2150a7b3400fSFugang Duan .swr_wait = 50, 2151a7b3400fSFugang Duan .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, 2152a7b3400fSFugang Duan .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, 2153a7b3400fSFugang Duan .ops = &eqos_imx_ops 2154a7b3400fSFugang Duan }; 2155a7b3400fSFugang Duan 2156*fc99c7abSDavid Wu struct eqos_ops eqos_rockchip_ops = { 2157*fc99c7abSDavid Wu .eqos_inval_desc = eqos_inval_desc_generic, 2158*fc99c7abSDavid Wu .eqos_flush_desc = eqos_flush_desc_generic, 2159*fc99c7abSDavid Wu .eqos_inval_buffer = eqos_inval_buffer_generic, 2160*fc99c7abSDavid Wu .eqos_flush_buffer = eqos_flush_buffer_generic, 2161*fc99c7abSDavid Wu .eqos_probe_resources = eqos_probe_resources_stm32, 2162*fc99c7abSDavid Wu .eqos_remove_resources = eqos_remove_resources_stm32, 2163*fc99c7abSDavid Wu .eqos_stop_resets = eqos_stop_resets_stm32, 2164*fc99c7abSDavid Wu .eqos_start_resets = eqos_start_resets_stm32, 2165*fc99c7abSDavid Wu .eqos_calibrate_pads = eqos_calibrate_pads_stm32, 2166*fc99c7abSDavid Wu .eqos_disable_calibration = eqos_disable_calibration_stm32, 2167*fc99c7abSDavid Wu .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32, 2168*fc99c7abSDavid Wu .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32, 2169*fc99c7abSDavid Wu .eqos_get_interface = eqos_get_interface_stm32 2170*fc99c7abSDavid Wu }; 2171*fc99c7abSDavid Wu 2172ba4dfef1SStephen Warren static const struct udevice_id eqos_ids[] = { 2173ba4dfef1SStephen Warren { 2174ba4dfef1SStephen Warren .compatible = "nvidia,tegra186-eqos", 2175ba4dfef1SStephen Warren .data = (ulong)&eqos_tegra186_config 2176ba4dfef1SStephen Warren }, 21777a4c4eddSChristophe Roullier { 21787a4c4eddSChristophe Roullier .compatible = "snps,dwmac-4.20a", 21797a4c4eddSChristophe Roullier .data = (ulong)&eqos_stm32_config 21807a4c4eddSChristophe Roullier }, 2181a7b3400fSFugang Duan { 2182a7b3400fSFugang Duan .compatible = "fsl,imx-eqos", 2183a7b3400fSFugang Duan .data = (ulong)&eqos_imx_config 2184a7b3400fSFugang Duan }, 21857a4c4eddSChristophe Roullier 2186ba4dfef1SStephen Warren { } 2187ba4dfef1SStephen Warren }; 2188ba4dfef1SStephen Warren 2189ba4dfef1SStephen Warren U_BOOT_DRIVER(eth_eqos) = { 2190ba4dfef1SStephen Warren .name = "eth_eqos", 2191ba4dfef1SStephen Warren .id = UCLASS_ETH, 2192a7b3400fSFugang Duan .of_match = of_match_ptr(eqos_ids), 2193ba4dfef1SStephen Warren .probe = eqos_probe, 2194ba4dfef1SStephen Warren .remove = eqos_remove, 2195ba4dfef1SStephen Warren .ops = &eqos_ops, 2196ba4dfef1SStephen Warren .priv_auto_alloc_size = sizeof(struct eqos_priv), 2197ba4dfef1SStephen Warren .platdata_auto_alloc_size = sizeof(struct eth_pdata), 2198ba4dfef1SStephen Warren }; 2199