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> 43ba4dfef1SStephen Warren 44ba4dfef1SStephen Warren /* Core registers */ 45ba4dfef1SStephen Warren 46ba4dfef1SStephen Warren #define EQOS_MAC_REGS_BASE 0x000 47ba4dfef1SStephen Warren struct eqos_mac_regs { 48ba4dfef1SStephen Warren uint32_t configuration; /* 0x000 */ 49ba4dfef1SStephen Warren uint32_t unused_004[(0x070 - 0x004) / 4]; /* 0x004 */ 50ba4dfef1SStephen Warren uint32_t q0_tx_flow_ctrl; /* 0x070 */ 51ba4dfef1SStephen Warren uint32_t unused_070[(0x090 - 0x074) / 4]; /* 0x074 */ 52ba4dfef1SStephen Warren uint32_t rx_flow_ctrl; /* 0x090 */ 53ba4dfef1SStephen Warren uint32_t unused_094; /* 0x094 */ 54ba4dfef1SStephen Warren uint32_t txq_prty_map0; /* 0x098 */ 55ba4dfef1SStephen Warren uint32_t unused_09c; /* 0x09c */ 56ba4dfef1SStephen Warren uint32_t rxq_ctrl0; /* 0x0a0 */ 57ba4dfef1SStephen Warren uint32_t unused_0a4; /* 0x0a4 */ 58ba4dfef1SStephen Warren uint32_t rxq_ctrl2; /* 0x0a8 */ 59ba4dfef1SStephen Warren uint32_t unused_0ac[(0x0dc - 0x0ac) / 4]; /* 0x0ac */ 60ba4dfef1SStephen Warren uint32_t us_tic_counter; /* 0x0dc */ 61ba4dfef1SStephen Warren uint32_t unused_0e0[(0x11c - 0x0e0) / 4]; /* 0x0e0 */ 62ba4dfef1SStephen Warren uint32_t hw_feature0; /* 0x11c */ 63ba4dfef1SStephen Warren uint32_t hw_feature1; /* 0x120 */ 64ba4dfef1SStephen Warren uint32_t hw_feature2; /* 0x124 */ 65ba4dfef1SStephen Warren uint32_t unused_128[(0x200 - 0x128) / 4]; /* 0x128 */ 66ba4dfef1SStephen Warren uint32_t mdio_address; /* 0x200 */ 67ba4dfef1SStephen Warren uint32_t mdio_data; /* 0x204 */ 68ba4dfef1SStephen Warren uint32_t unused_208[(0x300 - 0x208) / 4]; /* 0x208 */ 69ba4dfef1SStephen Warren uint32_t address0_high; /* 0x300 */ 70ba4dfef1SStephen Warren uint32_t address0_low; /* 0x304 */ 71ba4dfef1SStephen Warren }; 72ba4dfef1SStephen Warren 73ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_GPSLCE BIT(23) 74ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_CST BIT(21) 75ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_ACS BIT(20) 76ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_WD BIT(19) 77ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_JD BIT(17) 78ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_JE BIT(16) 79ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_PS BIT(15) 80ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_FES BIT(14) 81ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_DM BIT(13) 82ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_TE BIT(1) 83ba4dfef1SStephen Warren #define EQOS_MAC_CONFIGURATION_RE BIT(0) 84ba4dfef1SStephen Warren 85ba4dfef1SStephen Warren #define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT 16 86ba4dfef1SStephen Warren #define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_MASK 0xffff 87ba4dfef1SStephen Warren #define EQOS_MAC_Q0_TX_FLOW_CTRL_TFE BIT(1) 88ba4dfef1SStephen Warren 89ba4dfef1SStephen Warren #define EQOS_MAC_RX_FLOW_CTRL_RFE BIT(0) 90ba4dfef1SStephen Warren 91ba4dfef1SStephen Warren #define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_SHIFT 0 92ba4dfef1SStephen Warren #define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK 0xff 93ba4dfef1SStephen Warren 94ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT 0 95ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 96ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED 0 97ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB 2 987a4c4eddSChristophe Roullier #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV 1 99ba4dfef1SStephen Warren 100ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 101ba4dfef1SStephen Warren #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff 102ba4dfef1SStephen Warren 103ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT 6 104ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK 0x1f 105ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT 0 106ba4dfef1SStephen Warren #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK 0x1f 107ba4dfef1SStephen Warren 108ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21 109ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 110ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 111ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 1127a4c4eddSChristophe Roullier #define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 113ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) 114ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 115ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 116ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GOC_WRITE 1 117ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_C45E BIT(1) 118ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_ADDRESS_GB BIT(0) 119ba4dfef1SStephen Warren 120ba4dfef1SStephen Warren #define EQOS_MAC_MDIO_DATA_GD_MASK 0xffff 121ba4dfef1SStephen Warren 122ba4dfef1SStephen Warren #define EQOS_MTL_REGS_BASE 0xd00 123ba4dfef1SStephen Warren struct eqos_mtl_regs { 124ba4dfef1SStephen Warren uint32_t txq0_operation_mode; /* 0xd00 */ 125ba4dfef1SStephen Warren uint32_t unused_d04; /* 0xd04 */ 126ba4dfef1SStephen Warren uint32_t txq0_debug; /* 0xd08 */ 127ba4dfef1SStephen Warren uint32_t unused_d0c[(0xd18 - 0xd0c) / 4]; /* 0xd0c */ 128ba4dfef1SStephen Warren uint32_t txq0_quantum_weight; /* 0xd18 */ 129ba4dfef1SStephen Warren uint32_t unused_d1c[(0xd30 - 0xd1c) / 4]; /* 0xd1c */ 130ba4dfef1SStephen Warren uint32_t rxq0_operation_mode; /* 0xd30 */ 131ba4dfef1SStephen Warren uint32_t unused_d34; /* 0xd34 */ 132ba4dfef1SStephen Warren uint32_t rxq0_debug; /* 0xd38 */ 133ba4dfef1SStephen Warren }; 134ba4dfef1SStephen Warren 135ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT 16 136ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_MASK 0x1ff 137ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT 2 138ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_MASK 3 139ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED 2 140ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_TSF BIT(1) 141ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_OPERATION_MODE_FTQ BIT(0) 142ba4dfef1SStephen Warren 143ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_DEBUG_TXQSTS BIT(4) 144ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_DEBUG_TRCSTS_SHIFT 1 145ba4dfef1SStephen Warren #define EQOS_MTL_TXQ0_DEBUG_TRCSTS_MASK 3 146ba4dfef1SStephen Warren 147ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT 20 148ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_MASK 0x3ff 149ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT 14 150ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_MASK 0x3f 151ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT 8 152ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f 153ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7) 154ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5) 155ba4dfef1SStephen Warren 156ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16 157ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff 158ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_RXQSTS_SHIFT 4 159ba4dfef1SStephen Warren #define EQOS_MTL_RXQ0_DEBUG_RXQSTS_MASK 3 160ba4dfef1SStephen Warren 161ba4dfef1SStephen Warren #define EQOS_DMA_REGS_BASE 0x1000 162ba4dfef1SStephen Warren struct eqos_dma_regs { 163ba4dfef1SStephen Warren uint32_t mode; /* 0x1000 */ 164ba4dfef1SStephen Warren uint32_t sysbus_mode; /* 0x1004 */ 165ba4dfef1SStephen Warren uint32_t unused_1008[(0x1100 - 0x1008) / 4]; /* 0x1008 */ 166ba4dfef1SStephen Warren uint32_t ch0_control; /* 0x1100 */ 167ba4dfef1SStephen Warren uint32_t ch0_tx_control; /* 0x1104 */ 168ba4dfef1SStephen Warren uint32_t ch0_rx_control; /* 0x1108 */ 169ba4dfef1SStephen Warren uint32_t unused_110c; /* 0x110c */ 170ba4dfef1SStephen Warren uint32_t ch0_txdesc_list_haddress; /* 0x1110 */ 171ba4dfef1SStephen Warren uint32_t ch0_txdesc_list_address; /* 0x1114 */ 172ba4dfef1SStephen Warren uint32_t ch0_rxdesc_list_haddress; /* 0x1118 */ 173ba4dfef1SStephen Warren uint32_t ch0_rxdesc_list_address; /* 0x111c */ 174ba4dfef1SStephen Warren uint32_t ch0_txdesc_tail_pointer; /* 0x1120 */ 175ba4dfef1SStephen Warren uint32_t unused_1124; /* 0x1124 */ 176ba4dfef1SStephen Warren uint32_t ch0_rxdesc_tail_pointer; /* 0x1128 */ 177ba4dfef1SStephen Warren uint32_t ch0_txdesc_ring_length; /* 0x112c */ 178ba4dfef1SStephen Warren uint32_t ch0_rxdesc_ring_length; /* 0x1130 */ 179ba4dfef1SStephen Warren }; 180ba4dfef1SStephen Warren 181ba4dfef1SStephen Warren #define EQOS_DMA_MODE_SWR BIT(0) 182ba4dfef1SStephen Warren 183ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT 16 184ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK 0xf 185ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_EAME BIT(11) 186ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_BLEN16 BIT(3) 187ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_BLEN8 BIT(2) 188ba4dfef1SStephen Warren #define EQOS_DMA_SYSBUS_MODE_BLEN4 BIT(1) 189ba4dfef1SStephen Warren 190ba4dfef1SStephen Warren #define EQOS_DMA_CH0_CONTROL_PBLX8 BIT(16) 191ba4dfef1SStephen Warren 192ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT 16 193ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_TXPBL_MASK 0x3f 194ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_OSP BIT(4) 195ba4dfef1SStephen Warren #define EQOS_DMA_CH0_TX_CONTROL_ST BIT(0) 196ba4dfef1SStephen Warren 197ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT 16 198ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RXPBL_MASK 0x3f 199ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT 1 200ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_RBSZ_MASK 0x3fff 201ba4dfef1SStephen Warren #define EQOS_DMA_CH0_RX_CONTROL_SR BIT(0) 202ba4dfef1SStephen Warren 203ba4dfef1SStephen Warren /* These registers are Tegra186-specific */ 204ba4dfef1SStephen Warren #define EQOS_TEGRA186_REGS_BASE 0x8800 205ba4dfef1SStephen Warren struct eqos_tegra186_regs { 206ba4dfef1SStephen Warren uint32_t sdmemcomppadctrl; /* 0x8800 */ 207ba4dfef1SStephen Warren uint32_t auto_cal_config; /* 0x8804 */ 208ba4dfef1SStephen Warren uint32_t unused_8808; /* 0x8808 */ 209ba4dfef1SStephen Warren uint32_t auto_cal_status; /* 0x880c */ 210ba4dfef1SStephen Warren }; 211ba4dfef1SStephen Warren 212ba4dfef1SStephen Warren #define EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31) 213ba4dfef1SStephen Warren 214ba4dfef1SStephen Warren #define EQOS_AUTO_CAL_CONFIG_START BIT(31) 215ba4dfef1SStephen Warren #define EQOS_AUTO_CAL_CONFIG_ENABLE BIT(29) 216ba4dfef1SStephen Warren 217ba4dfef1SStephen Warren #define EQOS_AUTO_CAL_STATUS_ACTIVE BIT(31) 218ba4dfef1SStephen Warren 219ba4dfef1SStephen Warren /* Descriptors */ 220ba4dfef1SStephen Warren 221ba4dfef1SStephen Warren #define EQOS_DESCRIPTOR_WORDS 4 222ba4dfef1SStephen Warren #define EQOS_DESCRIPTOR_SIZE (EQOS_DESCRIPTOR_WORDS * 4) 223ba4dfef1SStephen Warren /* We assume ARCH_DMA_MINALIGN >= 16; 16 is the EQOS HW minimum */ 224ba4dfef1SStephen Warren #define EQOS_DESCRIPTOR_ALIGN ARCH_DMA_MINALIGN 225ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_TX 4 226ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_RX 4 227ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX) 228ba4dfef1SStephen Warren #define EQOS_DESCRIPTORS_SIZE ALIGN(EQOS_DESCRIPTORS_NUM * \ 229ba4dfef1SStephen Warren EQOS_DESCRIPTOR_SIZE, ARCH_DMA_MINALIGN) 230ba4dfef1SStephen Warren #define EQOS_BUFFER_ALIGN ARCH_DMA_MINALIGN 231ba4dfef1SStephen Warren #define EQOS_MAX_PACKET_SIZE ALIGN(1568, ARCH_DMA_MINALIGN) 232ba4dfef1SStephen Warren #define EQOS_RX_BUFFER_SIZE (EQOS_DESCRIPTORS_RX * EQOS_MAX_PACKET_SIZE) 233ba4dfef1SStephen Warren 234ba4dfef1SStephen Warren /* 235ba4dfef1SStephen Warren * Warn if the cache-line size is larger than the descriptor size. In such 236ba4dfef1SStephen Warren * cases the driver will likely fail because the CPU needs to flush the cache 237ba4dfef1SStephen Warren * when requeuing RX buffers, therefore descriptors written by the hardware 238ba4dfef1SStephen Warren * may be discarded. Architectures with full IO coherence, such as x86, do not 239ba4dfef1SStephen Warren * experience this issue, and hence are excluded from this condition. 240ba4dfef1SStephen Warren * 241ba4dfef1SStephen Warren * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause 242ba4dfef1SStephen Warren * the driver to allocate descriptors from a pool of non-cached memory. 243ba4dfef1SStephen Warren */ 244ba4dfef1SStephen Warren #if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN 245ba4dfef1SStephen Warren #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ 246ba4dfef1SStephen Warren !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) 247ba4dfef1SStephen Warren #warning Cache line size is larger than descriptor size 248ba4dfef1SStephen Warren #endif 249ba4dfef1SStephen Warren #endif 250ba4dfef1SStephen Warren 251ba4dfef1SStephen Warren struct eqos_desc { 252ba4dfef1SStephen Warren u32 des0; 253ba4dfef1SStephen Warren u32 des1; 254ba4dfef1SStephen Warren u32 des2; 255ba4dfef1SStephen Warren u32 des3; 256ba4dfef1SStephen Warren }; 257ba4dfef1SStephen Warren 258ba4dfef1SStephen Warren #define EQOS_DESC3_OWN BIT(31) 259ba4dfef1SStephen Warren #define EQOS_DESC3_FD BIT(29) 260ba4dfef1SStephen Warren #define EQOS_DESC3_LD BIT(28) 261ba4dfef1SStephen Warren #define EQOS_DESC3_BUF1V BIT(24) 262ba4dfef1SStephen Warren 263ba4dfef1SStephen Warren struct eqos_config { 264ba4dfef1SStephen Warren bool reg_access_always_ok; 2657a4c4eddSChristophe Roullier int mdio_wait; 2667a4c4eddSChristophe Roullier int swr_wait; 2677a4c4eddSChristophe Roullier int config_mac; 2687a4c4eddSChristophe Roullier int config_mac_mdio; 2697a4c4eddSChristophe Roullier phy_interface_t (*interface)(struct udevice *dev); 2707a4c4eddSChristophe Roullier struct eqos_ops *ops; 2717a4c4eddSChristophe Roullier }; 2727a4c4eddSChristophe Roullier 2737a4c4eddSChristophe Roullier struct eqos_ops { 2747a4c4eddSChristophe Roullier void (*eqos_inval_desc)(void *desc); 2757a4c4eddSChristophe Roullier void (*eqos_flush_desc)(void *desc); 2767a4c4eddSChristophe Roullier void (*eqos_inval_buffer)(void *buf, size_t size); 2777a4c4eddSChristophe Roullier void (*eqos_flush_buffer)(void *buf, size_t size); 2787a4c4eddSChristophe Roullier int (*eqos_probe_resources)(struct udevice *dev); 2797a4c4eddSChristophe Roullier int (*eqos_remove_resources)(struct udevice *dev); 2807a4c4eddSChristophe Roullier int (*eqos_stop_resets)(struct udevice *dev); 2817a4c4eddSChristophe Roullier int (*eqos_start_resets)(struct udevice *dev); 2827a4c4eddSChristophe Roullier void (*eqos_stop_clks)(struct udevice *dev); 2837a4c4eddSChristophe Roullier int (*eqos_start_clks)(struct udevice *dev); 2847a4c4eddSChristophe Roullier int (*eqos_calibrate_pads)(struct udevice *dev); 2857a4c4eddSChristophe Roullier int (*eqos_disable_calibration)(struct udevice *dev); 2867a4c4eddSChristophe Roullier int (*eqos_set_tx_clk_speed)(struct udevice *dev); 2877a4c4eddSChristophe Roullier ulong (*eqos_get_tick_clk_rate)(struct udevice *dev); 288ba4dfef1SStephen Warren }; 289ba4dfef1SStephen Warren 290ba4dfef1SStephen Warren struct eqos_priv { 291ba4dfef1SStephen Warren struct udevice *dev; 292ba4dfef1SStephen Warren const struct eqos_config *config; 293ba4dfef1SStephen Warren fdt_addr_t regs; 294ba4dfef1SStephen Warren struct eqos_mac_regs *mac_regs; 295ba4dfef1SStephen Warren struct eqos_mtl_regs *mtl_regs; 296ba4dfef1SStephen Warren struct eqos_dma_regs *dma_regs; 297ba4dfef1SStephen Warren struct eqos_tegra186_regs *tegra186_regs; 298ba4dfef1SStephen Warren struct reset_ctl reset_ctl; 299ba4dfef1SStephen Warren struct gpio_desc phy_reset_gpio; 300ba4dfef1SStephen Warren struct clk clk_master_bus; 301ba4dfef1SStephen Warren struct clk clk_rx; 302ba4dfef1SStephen Warren struct clk clk_ptp_ref; 303ba4dfef1SStephen Warren struct clk clk_tx; 3047a4c4eddSChristophe Roullier struct clk clk_ck; 305ba4dfef1SStephen Warren struct clk clk_slave_bus; 306ba4dfef1SStephen Warren struct mii_dev *mii; 307ba4dfef1SStephen Warren struct phy_device *phy; 30883d31c08SPatrick Delaunay int phyaddr; 30983d31c08SPatrick Delaunay u32 max_speed; 310ba4dfef1SStephen Warren void *descs; 311ba4dfef1SStephen Warren struct eqos_desc *tx_descs; 312ba4dfef1SStephen Warren struct eqos_desc *rx_descs; 313ba4dfef1SStephen Warren int tx_desc_idx, rx_desc_idx; 314ba4dfef1SStephen Warren void *tx_dma_buf; 315ba4dfef1SStephen Warren void *rx_dma_buf; 316ba4dfef1SStephen Warren void *rx_pkt; 317ba4dfef1SStephen Warren bool started; 318ba4dfef1SStephen Warren bool reg_access_ok; 319ba4dfef1SStephen Warren }; 320ba4dfef1SStephen Warren 321ba4dfef1SStephen Warren /* 322ba4dfef1SStephen Warren * TX and RX descriptors are 16 bytes. This causes problems with the cache 323ba4dfef1SStephen Warren * maintenance on CPUs where the cache-line size exceeds the size of these 324ba4dfef1SStephen Warren * descriptors. What will happen is that when the driver receives a packet 325ba4dfef1SStephen Warren * it will be immediately requeued for the hardware to reuse. The CPU will 326ba4dfef1SStephen Warren * therefore need to flush the cache-line containing the descriptor, which 327ba4dfef1SStephen Warren * will cause all other descriptors in the same cache-line to be flushed 328ba4dfef1SStephen Warren * along with it. If one of those descriptors had been written to by the 329ba4dfef1SStephen Warren * device those changes (and the associated packet) will be lost. 330ba4dfef1SStephen Warren * 331ba4dfef1SStephen Warren * To work around this, we make use of non-cached memory if available. If 332ba4dfef1SStephen Warren * descriptors are mapped uncached there's no need to manually flush them 333ba4dfef1SStephen Warren * or invalidate them. 334ba4dfef1SStephen Warren * 335ba4dfef1SStephen Warren * Note that this only applies to descriptors. The packet data buffers do 336ba4dfef1SStephen Warren * not have the same constraints since they are 1536 bytes large, so they 337ba4dfef1SStephen Warren * are unlikely to share cache-lines. 338ba4dfef1SStephen Warren */ 339ba4dfef1SStephen Warren static void *eqos_alloc_descs(unsigned int num) 340ba4dfef1SStephen Warren { 341ba4dfef1SStephen Warren #ifdef CONFIG_SYS_NONCACHED_MEMORY 342ba4dfef1SStephen Warren return (void *)noncached_alloc(EQOS_DESCRIPTORS_SIZE, 343ba4dfef1SStephen Warren EQOS_DESCRIPTOR_ALIGN); 344ba4dfef1SStephen Warren #else 345ba4dfef1SStephen Warren return memalign(EQOS_DESCRIPTOR_ALIGN, EQOS_DESCRIPTORS_SIZE); 346ba4dfef1SStephen Warren #endif 347ba4dfef1SStephen Warren } 348ba4dfef1SStephen Warren 349ba4dfef1SStephen Warren static void eqos_free_descs(void *descs) 350ba4dfef1SStephen Warren { 351ba4dfef1SStephen Warren #ifdef CONFIG_SYS_NONCACHED_MEMORY 352ba4dfef1SStephen Warren /* FIXME: noncached_alloc() has no opposite */ 353ba4dfef1SStephen Warren #else 354ba4dfef1SStephen Warren free(descs); 355ba4dfef1SStephen Warren #endif 356ba4dfef1SStephen Warren } 357ba4dfef1SStephen Warren 3587a4c4eddSChristophe Roullier static void eqos_inval_desc_tegra186(void *desc) 359ba4dfef1SStephen Warren { 360ba4dfef1SStephen Warren #ifndef CONFIG_SYS_NONCACHED_MEMORY 361ba4dfef1SStephen Warren unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); 362ba4dfef1SStephen Warren unsigned long end = ALIGN(start + EQOS_DESCRIPTOR_SIZE, 363ba4dfef1SStephen Warren ARCH_DMA_MINALIGN); 364ba4dfef1SStephen Warren 365ba4dfef1SStephen Warren invalidate_dcache_range(start, end); 366ba4dfef1SStephen Warren #endif 367ba4dfef1SStephen Warren } 368ba4dfef1SStephen Warren 3697a4c4eddSChristophe Roullier static void eqos_inval_desc_stm32(void *desc) 3707a4c4eddSChristophe Roullier { 3717a4c4eddSChristophe Roullier #ifndef CONFIG_SYS_NONCACHED_MEMORY 3727a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); 3737a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, 3747a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 3757a4c4eddSChristophe Roullier 3767a4c4eddSChristophe Roullier invalidate_dcache_range(start, end); 3777a4c4eddSChristophe Roullier #endif 3787a4c4eddSChristophe Roullier } 3797a4c4eddSChristophe Roullier 3807a4c4eddSChristophe Roullier static void eqos_flush_desc_tegra186(void *desc) 381ba4dfef1SStephen Warren { 382ba4dfef1SStephen Warren #ifndef CONFIG_SYS_NONCACHED_MEMORY 383ba4dfef1SStephen Warren flush_cache((unsigned long)desc, EQOS_DESCRIPTOR_SIZE); 384ba4dfef1SStephen Warren #endif 385ba4dfef1SStephen Warren } 386ba4dfef1SStephen Warren 3877a4c4eddSChristophe Roullier static void eqos_flush_desc_stm32(void *desc) 3887a4c4eddSChristophe Roullier { 3897a4c4eddSChristophe Roullier #ifndef CONFIG_SYS_NONCACHED_MEMORY 3907a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); 3917a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, 3927a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 3937a4c4eddSChristophe Roullier 3947a4c4eddSChristophe Roullier flush_dcache_range(start, end); 3957a4c4eddSChristophe Roullier #endif 3967a4c4eddSChristophe Roullier } 3977a4c4eddSChristophe Roullier 3987a4c4eddSChristophe Roullier static void eqos_inval_buffer_tegra186(void *buf, size_t size) 399ba4dfef1SStephen Warren { 400ba4dfef1SStephen Warren unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); 401ba4dfef1SStephen Warren unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); 402ba4dfef1SStephen Warren 403ba4dfef1SStephen Warren invalidate_dcache_range(start, end); 404ba4dfef1SStephen Warren } 405ba4dfef1SStephen Warren 4067a4c4eddSChristophe Roullier static void eqos_inval_buffer_stm32(void *buf, size_t size) 4077a4c4eddSChristophe Roullier { 4087a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); 4097a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)buf + size, 4107a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 4117a4c4eddSChristophe Roullier 4127a4c4eddSChristophe Roullier invalidate_dcache_range(start, end); 4137a4c4eddSChristophe Roullier } 4147a4c4eddSChristophe Roullier 4157a4c4eddSChristophe Roullier static void eqos_flush_buffer_tegra186(void *buf, size_t size) 416ba4dfef1SStephen Warren { 417ba4dfef1SStephen Warren flush_cache((unsigned long)buf, size); 418ba4dfef1SStephen Warren } 419ba4dfef1SStephen Warren 4207a4c4eddSChristophe Roullier static void eqos_flush_buffer_stm32(void *buf, size_t size) 4217a4c4eddSChristophe Roullier { 4227a4c4eddSChristophe Roullier unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); 4237a4c4eddSChristophe Roullier unsigned long end = roundup((unsigned long)buf + size, 4247a4c4eddSChristophe Roullier ARCH_DMA_MINALIGN); 4257a4c4eddSChristophe Roullier 4267a4c4eddSChristophe Roullier flush_dcache_range(start, end); 4277a4c4eddSChristophe Roullier } 4287a4c4eddSChristophe Roullier 429ba4dfef1SStephen Warren static int eqos_mdio_wait_idle(struct eqos_priv *eqos) 430ba4dfef1SStephen Warren { 431b491b498SJon Lin return wait_for_bit_le32(&eqos->mac_regs->mdio_address, 432b491b498SJon Lin EQOS_MAC_MDIO_ADDRESS_GB, false, 433b491b498SJon Lin 1000000, true); 434ba4dfef1SStephen Warren } 435ba4dfef1SStephen Warren 436ba4dfef1SStephen Warren static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, 437ba4dfef1SStephen Warren int mdio_reg) 438ba4dfef1SStephen Warren { 439ba4dfef1SStephen Warren struct eqos_priv *eqos = bus->priv; 440ba4dfef1SStephen Warren u32 val; 441ba4dfef1SStephen Warren int ret; 442ba4dfef1SStephen Warren 443ba4dfef1SStephen Warren debug("%s(dev=%p, addr=%x, reg=%d):\n", __func__, eqos->dev, mdio_addr, 444ba4dfef1SStephen Warren mdio_reg); 445ba4dfef1SStephen Warren 446ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 447ba4dfef1SStephen Warren if (ret) { 44890aa625cSMasahiro Yamada pr_err("MDIO not idle at entry"); 449ba4dfef1SStephen Warren return ret; 450ba4dfef1SStephen Warren } 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_READ << 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 val = readl(&eqos->mac_regs->mdio_data); 473ba4dfef1SStephen Warren val &= EQOS_MAC_MDIO_DATA_GD_MASK; 474ba4dfef1SStephen Warren 475ba4dfef1SStephen Warren debug("%s: val=%x\n", __func__, val); 476ba4dfef1SStephen Warren 477ba4dfef1SStephen Warren return val; 478ba4dfef1SStephen Warren } 479ba4dfef1SStephen Warren 480ba4dfef1SStephen Warren static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, 481ba4dfef1SStephen Warren int mdio_reg, u16 mdio_val) 482ba4dfef1SStephen Warren { 483ba4dfef1SStephen Warren struct eqos_priv *eqos = bus->priv; 484ba4dfef1SStephen Warren u32 val; 485ba4dfef1SStephen Warren int ret; 486ba4dfef1SStephen Warren 487ba4dfef1SStephen Warren debug("%s(dev=%p, addr=%x, reg=%d, val=%x):\n", __func__, eqos->dev, 488ba4dfef1SStephen Warren mdio_addr, mdio_reg, mdio_val); 489ba4dfef1SStephen Warren 490ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 491ba4dfef1SStephen Warren if (ret) { 49290aa625cSMasahiro Yamada pr_err("MDIO not idle at entry"); 493ba4dfef1SStephen Warren return ret; 494ba4dfef1SStephen Warren } 495ba4dfef1SStephen Warren 496ba4dfef1SStephen Warren writel(mdio_val, &eqos->mac_regs->mdio_data); 497ba4dfef1SStephen Warren 498ba4dfef1SStephen Warren val = readl(&eqos->mac_regs->mdio_address); 499ba4dfef1SStephen Warren val &= EQOS_MAC_MDIO_ADDRESS_SKAP | 500ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_C45E; 501ba4dfef1SStephen Warren val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | 502ba4dfef1SStephen Warren (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | 5037a4c4eddSChristophe Roullier (eqos->config->config_mac_mdio << 504ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | 505ba4dfef1SStephen Warren (EQOS_MAC_MDIO_ADDRESS_GOC_WRITE << 506ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | 507ba4dfef1SStephen Warren EQOS_MAC_MDIO_ADDRESS_GB; 508ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->mdio_address); 509ba4dfef1SStephen Warren 5107a4c4eddSChristophe Roullier udelay(eqos->config->mdio_wait); 511ba4dfef1SStephen Warren 512ba4dfef1SStephen Warren ret = eqos_mdio_wait_idle(eqos); 513ba4dfef1SStephen Warren if (ret) { 51490aa625cSMasahiro Yamada pr_err("MDIO read didn't complete"); 515ba4dfef1SStephen Warren return ret; 516ba4dfef1SStephen Warren } 517ba4dfef1SStephen Warren 518ba4dfef1SStephen Warren return 0; 519ba4dfef1SStephen Warren } 520ba4dfef1SStephen Warren 521ba4dfef1SStephen Warren static int eqos_start_clks_tegra186(struct udevice *dev) 522ba4dfef1SStephen Warren { 523ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 524ba4dfef1SStephen Warren int ret; 525ba4dfef1SStephen Warren 526ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 527ba4dfef1SStephen Warren 528ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_slave_bus); 529ba4dfef1SStephen Warren if (ret < 0) { 53090aa625cSMasahiro Yamada pr_err("clk_enable(clk_slave_bus) failed: %d", ret); 531ba4dfef1SStephen Warren goto err; 532ba4dfef1SStephen Warren } 533ba4dfef1SStephen Warren 534ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_master_bus); 535ba4dfef1SStephen Warren if (ret < 0) { 53690aa625cSMasahiro Yamada pr_err("clk_enable(clk_master_bus) failed: %d", ret); 537ba4dfef1SStephen Warren goto err_disable_clk_slave_bus; 538ba4dfef1SStephen Warren } 539ba4dfef1SStephen Warren 540ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_rx); 541ba4dfef1SStephen Warren if (ret < 0) { 54290aa625cSMasahiro Yamada pr_err("clk_enable(clk_rx) failed: %d", ret); 543ba4dfef1SStephen Warren goto err_disable_clk_master_bus; 544ba4dfef1SStephen Warren } 545ba4dfef1SStephen Warren 546ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_ptp_ref); 547ba4dfef1SStephen Warren if (ret < 0) { 54890aa625cSMasahiro Yamada pr_err("clk_enable(clk_ptp_ref) failed: %d", ret); 549ba4dfef1SStephen Warren goto err_disable_clk_rx; 550ba4dfef1SStephen Warren } 551ba4dfef1SStephen Warren 552ba4dfef1SStephen Warren ret = clk_set_rate(&eqos->clk_ptp_ref, 125 * 1000 * 1000); 553ba4dfef1SStephen Warren if (ret < 0) { 55490aa625cSMasahiro Yamada pr_err("clk_set_rate(clk_ptp_ref) failed: %d", ret); 555ba4dfef1SStephen Warren goto err_disable_clk_ptp_ref; 556ba4dfef1SStephen Warren } 557ba4dfef1SStephen Warren 558ba4dfef1SStephen Warren ret = clk_enable(&eqos->clk_tx); 559ba4dfef1SStephen Warren if (ret < 0) { 56090aa625cSMasahiro Yamada pr_err("clk_enable(clk_tx) failed: %d", ret); 561ba4dfef1SStephen Warren goto err_disable_clk_ptp_ref; 562ba4dfef1SStephen Warren } 563ba4dfef1SStephen Warren 564ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 565ba4dfef1SStephen Warren return 0; 566ba4dfef1SStephen Warren 567ba4dfef1SStephen Warren err_disable_clk_ptp_ref: 568ba4dfef1SStephen Warren clk_disable(&eqos->clk_ptp_ref); 569ba4dfef1SStephen Warren err_disable_clk_rx: 570ba4dfef1SStephen Warren clk_disable(&eqos->clk_rx); 571ba4dfef1SStephen Warren err_disable_clk_master_bus: 572ba4dfef1SStephen Warren clk_disable(&eqos->clk_master_bus); 573ba4dfef1SStephen Warren err_disable_clk_slave_bus: 574ba4dfef1SStephen Warren clk_disable(&eqos->clk_slave_bus); 575ba4dfef1SStephen Warren err: 576ba4dfef1SStephen Warren debug("%s: FAILED: %d\n", __func__, ret); 577ba4dfef1SStephen Warren return ret; 578ba4dfef1SStephen Warren } 579ba4dfef1SStephen Warren 5807a4c4eddSChristophe Roullier static int eqos_start_clks_stm32(struct udevice *dev) 5817a4c4eddSChristophe Roullier { 5827a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 5837a4c4eddSChristophe Roullier int ret; 5847a4c4eddSChristophe Roullier 5857a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 5867a4c4eddSChristophe Roullier 5877a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_master_bus); 5887a4c4eddSChristophe Roullier if (ret < 0) { 5897a4c4eddSChristophe Roullier pr_err("clk_enable(clk_master_bus) failed: %d", ret); 5907a4c4eddSChristophe Roullier goto err; 5917a4c4eddSChristophe Roullier } 5927a4c4eddSChristophe Roullier 5937a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_rx); 5947a4c4eddSChristophe Roullier if (ret < 0) { 5957a4c4eddSChristophe Roullier pr_err("clk_enable(clk_rx) failed: %d", ret); 5967a4c4eddSChristophe Roullier goto err_disable_clk_master_bus; 5977a4c4eddSChristophe Roullier } 5987a4c4eddSChristophe Roullier 5997a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_tx); 6007a4c4eddSChristophe Roullier if (ret < 0) { 6017a4c4eddSChristophe Roullier pr_err("clk_enable(clk_tx) failed: %d", ret); 6027a4c4eddSChristophe Roullier goto err_disable_clk_rx; 6037a4c4eddSChristophe Roullier } 6047a4c4eddSChristophe Roullier 6057a4c4eddSChristophe Roullier if (clk_valid(&eqos->clk_ck)) { 6067a4c4eddSChristophe Roullier ret = clk_enable(&eqos->clk_ck); 6077a4c4eddSChristophe Roullier if (ret < 0) { 6087a4c4eddSChristophe Roullier pr_err("clk_enable(clk_ck) failed: %d", ret); 6097a4c4eddSChristophe Roullier goto err_disable_clk_tx; 6107a4c4eddSChristophe Roullier } 6117a4c4eddSChristophe Roullier } 6127a4c4eddSChristophe Roullier 6137a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 6147a4c4eddSChristophe Roullier return 0; 6157a4c4eddSChristophe Roullier 6167a4c4eddSChristophe Roullier err_disable_clk_tx: 6177a4c4eddSChristophe Roullier clk_disable(&eqos->clk_tx); 6187a4c4eddSChristophe Roullier err_disable_clk_rx: 6197a4c4eddSChristophe Roullier clk_disable(&eqos->clk_rx); 6207a4c4eddSChristophe Roullier err_disable_clk_master_bus: 6217a4c4eddSChristophe Roullier clk_disable(&eqos->clk_master_bus); 6227a4c4eddSChristophe Roullier err: 6237a4c4eddSChristophe Roullier debug("%s: FAILED: %d\n", __func__, ret); 6247a4c4eddSChristophe Roullier return ret; 6257a4c4eddSChristophe Roullier } 6267a4c4eddSChristophe Roullier 6278aaada72SPatrick Delaunay static void eqos_stop_clks_tegra186(struct udevice *dev) 628ba4dfef1SStephen Warren { 629ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 630ba4dfef1SStephen Warren 631ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 632ba4dfef1SStephen Warren 633ba4dfef1SStephen Warren clk_disable(&eqos->clk_tx); 634ba4dfef1SStephen Warren clk_disable(&eqos->clk_ptp_ref); 635ba4dfef1SStephen Warren clk_disable(&eqos->clk_rx); 636ba4dfef1SStephen Warren clk_disable(&eqos->clk_master_bus); 637ba4dfef1SStephen Warren clk_disable(&eqos->clk_slave_bus); 638ba4dfef1SStephen Warren 639ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 640ba4dfef1SStephen Warren } 641ba4dfef1SStephen Warren 6428aaada72SPatrick Delaunay static void eqos_stop_clks_stm32(struct udevice *dev) 6437a4c4eddSChristophe Roullier { 6447a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 6457a4c4eddSChristophe Roullier 6467a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 6477a4c4eddSChristophe Roullier 6487a4c4eddSChristophe Roullier clk_disable(&eqos->clk_tx); 6497a4c4eddSChristophe Roullier clk_disable(&eqos->clk_rx); 6507a4c4eddSChristophe Roullier clk_disable(&eqos->clk_master_bus); 6517a4c4eddSChristophe Roullier if (clk_valid(&eqos->clk_ck)) 6527a4c4eddSChristophe Roullier clk_disable(&eqos->clk_ck); 6537a4c4eddSChristophe Roullier 6547a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 6557a4c4eddSChristophe Roullier } 6567a4c4eddSChristophe Roullier 657ba4dfef1SStephen Warren static int eqos_start_resets_tegra186(struct udevice *dev) 658ba4dfef1SStephen Warren { 659ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 660ba4dfef1SStephen Warren int ret; 661ba4dfef1SStephen Warren 662ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 663ba4dfef1SStephen Warren 664ba4dfef1SStephen Warren ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); 665ba4dfef1SStephen Warren if (ret < 0) { 66690aa625cSMasahiro Yamada pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret); 667ba4dfef1SStephen Warren return ret; 668ba4dfef1SStephen Warren } 669ba4dfef1SStephen Warren 670ba4dfef1SStephen Warren udelay(2); 671ba4dfef1SStephen Warren 672ba4dfef1SStephen Warren ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); 673ba4dfef1SStephen Warren if (ret < 0) { 67490aa625cSMasahiro Yamada pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret); 675ba4dfef1SStephen Warren return ret; 676ba4dfef1SStephen Warren } 677ba4dfef1SStephen Warren 678ba4dfef1SStephen Warren ret = reset_assert(&eqos->reset_ctl); 679ba4dfef1SStephen Warren if (ret < 0) { 68090aa625cSMasahiro Yamada pr_err("reset_assert() failed: %d", ret); 681ba4dfef1SStephen Warren return ret; 682ba4dfef1SStephen Warren } 683ba4dfef1SStephen Warren 684ba4dfef1SStephen Warren udelay(2); 685ba4dfef1SStephen Warren 686ba4dfef1SStephen Warren ret = reset_deassert(&eqos->reset_ctl); 687ba4dfef1SStephen Warren if (ret < 0) { 68890aa625cSMasahiro Yamada pr_err("reset_deassert() failed: %d", ret); 689ba4dfef1SStephen Warren return ret; 690ba4dfef1SStephen Warren } 691ba4dfef1SStephen Warren 692ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 693ba4dfef1SStephen Warren return 0; 694ba4dfef1SStephen Warren } 695ba4dfef1SStephen Warren 6967a4c4eddSChristophe Roullier static int eqos_start_resets_stm32(struct udevice *dev) 6977a4c4eddSChristophe Roullier { 6985bd3c538SChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 6995bd3c538SChristophe Roullier int ret; 7005bd3c538SChristophe Roullier 7015bd3c538SChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 7025bd3c538SChristophe Roullier if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { 7035bd3c538SChristophe Roullier ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); 7045bd3c538SChristophe Roullier if (ret < 0) { 7055bd3c538SChristophe Roullier pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", 7065bd3c538SChristophe Roullier ret); 7075bd3c538SChristophe Roullier return ret; 7085bd3c538SChristophe Roullier } 7095bd3c538SChristophe Roullier 7105bd3c538SChristophe Roullier udelay(2); 7115bd3c538SChristophe Roullier 7125bd3c538SChristophe Roullier ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); 7135bd3c538SChristophe Roullier if (ret < 0) { 7145bd3c538SChristophe Roullier pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", 7155bd3c538SChristophe Roullier ret); 7165bd3c538SChristophe Roullier return ret; 7175bd3c538SChristophe Roullier } 7185bd3c538SChristophe Roullier } 7195bd3c538SChristophe Roullier debug("%s: OK\n", __func__); 7205bd3c538SChristophe Roullier 7217a4c4eddSChristophe Roullier return 0; 7227a4c4eddSChristophe Roullier } 7237a4c4eddSChristophe Roullier 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 751ba4dfef1SStephen Warren static int eqos_calibrate_pads_tegra186(struct udevice *dev) 752ba4dfef1SStephen Warren { 753ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 754ba4dfef1SStephen Warren int ret; 755ba4dfef1SStephen Warren 756ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 757ba4dfef1SStephen Warren 758ba4dfef1SStephen Warren setbits_le32(&eqos->tegra186_regs->sdmemcomppadctrl, 759ba4dfef1SStephen Warren EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD); 760ba4dfef1SStephen Warren 761ba4dfef1SStephen Warren udelay(1); 762ba4dfef1SStephen Warren 763ba4dfef1SStephen Warren setbits_le32(&eqos->tegra186_regs->auto_cal_config, 764ba4dfef1SStephen Warren EQOS_AUTO_CAL_CONFIG_START | EQOS_AUTO_CAL_CONFIG_ENABLE); 765ba4dfef1SStephen Warren 766b491b498SJon Lin ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status, 767ba4dfef1SStephen Warren EQOS_AUTO_CAL_STATUS_ACTIVE, true, 10, false); 768ba4dfef1SStephen Warren if (ret) { 76990aa625cSMasahiro Yamada pr_err("calibrate didn't start"); 770ba4dfef1SStephen Warren goto failed; 771ba4dfef1SStephen Warren } 772ba4dfef1SStephen Warren 773b491b498SJon Lin ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status, 774ba4dfef1SStephen Warren EQOS_AUTO_CAL_STATUS_ACTIVE, false, 10, false); 775ba4dfef1SStephen Warren if (ret) { 77690aa625cSMasahiro Yamada pr_err("calibrate didn't finish"); 777ba4dfef1SStephen Warren goto failed; 778ba4dfef1SStephen Warren } 779ba4dfef1SStephen Warren 780ba4dfef1SStephen Warren ret = 0; 781ba4dfef1SStephen Warren 782ba4dfef1SStephen Warren failed: 783ba4dfef1SStephen Warren clrbits_le32(&eqos->tegra186_regs->sdmemcomppadctrl, 784ba4dfef1SStephen Warren EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD); 785ba4dfef1SStephen Warren 786ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 787ba4dfef1SStephen Warren 788ba4dfef1SStephen Warren return ret; 789ba4dfef1SStephen Warren } 790ba4dfef1SStephen Warren 791ba4dfef1SStephen Warren static int eqos_disable_calibration_tegra186(struct udevice *dev) 792ba4dfef1SStephen Warren { 793ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 794ba4dfef1SStephen Warren 795ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 796ba4dfef1SStephen Warren 797ba4dfef1SStephen Warren clrbits_le32(&eqos->tegra186_regs->auto_cal_config, 798ba4dfef1SStephen Warren EQOS_AUTO_CAL_CONFIG_ENABLE); 799ba4dfef1SStephen Warren 800ba4dfef1SStephen Warren return 0; 801ba4dfef1SStephen Warren } 802ba4dfef1SStephen Warren 803ba4dfef1SStephen Warren static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev) 804ba4dfef1SStephen Warren { 805ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 806ba4dfef1SStephen Warren 807ba4dfef1SStephen Warren return clk_get_rate(&eqos->clk_slave_bus); 808ba4dfef1SStephen Warren } 809ba4dfef1SStephen Warren 8107a4c4eddSChristophe Roullier static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) 8117a4c4eddSChristophe Roullier { 8127a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 8137a4c4eddSChristophe Roullier 8147a4c4eddSChristophe Roullier return clk_get_rate(&eqos->clk_master_bus); 8157a4c4eddSChristophe Roullier } 8167a4c4eddSChristophe Roullier 8177a4c4eddSChristophe Roullier static int eqos_calibrate_pads_stm32(struct udevice *dev) 8187a4c4eddSChristophe Roullier { 8197a4c4eddSChristophe Roullier return 0; 8207a4c4eddSChristophe Roullier } 8217a4c4eddSChristophe Roullier 8227a4c4eddSChristophe Roullier static int eqos_disable_calibration_stm32(struct udevice *dev) 8237a4c4eddSChristophe Roullier { 8247a4c4eddSChristophe Roullier return 0; 8257a4c4eddSChristophe Roullier } 8267a4c4eddSChristophe Roullier 827ba4dfef1SStephen Warren static int eqos_set_full_duplex(struct udevice *dev) 828ba4dfef1SStephen Warren { 829ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 830ba4dfef1SStephen Warren 831ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 832ba4dfef1SStephen Warren 833ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->configuration, EQOS_MAC_CONFIGURATION_DM); 834ba4dfef1SStephen Warren 835ba4dfef1SStephen Warren return 0; 836ba4dfef1SStephen Warren } 837ba4dfef1SStephen Warren 838ba4dfef1SStephen Warren static int eqos_set_half_duplex(struct udevice *dev) 839ba4dfef1SStephen Warren { 840ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 841ba4dfef1SStephen Warren 842ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 843ba4dfef1SStephen Warren 844ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->configuration, EQOS_MAC_CONFIGURATION_DM); 845ba4dfef1SStephen Warren 846ba4dfef1SStephen Warren /* WAR: Flush TX queue when switching to half-duplex */ 847ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->txq0_operation_mode, 848ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_FTQ); 849ba4dfef1SStephen Warren 850ba4dfef1SStephen Warren return 0; 851ba4dfef1SStephen Warren } 852ba4dfef1SStephen Warren 853ba4dfef1SStephen Warren static int eqos_set_gmii_speed(struct udevice *dev) 854ba4dfef1SStephen Warren { 855ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 856ba4dfef1SStephen Warren 857ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 858ba4dfef1SStephen Warren 859ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->configuration, 860ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_PS | EQOS_MAC_CONFIGURATION_FES); 861ba4dfef1SStephen Warren 862ba4dfef1SStephen Warren return 0; 863ba4dfef1SStephen Warren } 864ba4dfef1SStephen Warren 865ba4dfef1SStephen Warren static int eqos_set_mii_speed_100(struct udevice *dev) 866ba4dfef1SStephen Warren { 867ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 868ba4dfef1SStephen Warren 869ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 870ba4dfef1SStephen Warren 871ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->configuration, 872ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_PS | EQOS_MAC_CONFIGURATION_FES); 873ba4dfef1SStephen Warren 874ba4dfef1SStephen Warren return 0; 875ba4dfef1SStephen Warren } 876ba4dfef1SStephen Warren 877ba4dfef1SStephen Warren static int eqos_set_mii_speed_10(struct udevice *dev) 878ba4dfef1SStephen Warren { 879ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 880ba4dfef1SStephen Warren 881ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 882ba4dfef1SStephen Warren 883ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mac_regs->configuration, 884ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_FES, EQOS_MAC_CONFIGURATION_PS); 885ba4dfef1SStephen Warren 886ba4dfef1SStephen Warren return 0; 887ba4dfef1SStephen Warren } 888ba4dfef1SStephen Warren 889ba4dfef1SStephen Warren static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) 890ba4dfef1SStephen Warren { 891ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 892ba4dfef1SStephen Warren ulong rate; 893ba4dfef1SStephen Warren int ret; 894ba4dfef1SStephen Warren 895ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 896ba4dfef1SStephen Warren 897ba4dfef1SStephen Warren switch (eqos->phy->speed) { 898ba4dfef1SStephen Warren case SPEED_1000: 899ba4dfef1SStephen Warren rate = 125 * 1000 * 1000; 900ba4dfef1SStephen Warren break; 901ba4dfef1SStephen Warren case SPEED_100: 902ba4dfef1SStephen Warren rate = 25 * 1000 * 1000; 903ba4dfef1SStephen Warren break; 904ba4dfef1SStephen Warren case SPEED_10: 905ba4dfef1SStephen Warren rate = 2.5 * 1000 * 1000; 906ba4dfef1SStephen Warren break; 907ba4dfef1SStephen Warren default: 90890aa625cSMasahiro Yamada pr_err("invalid speed %d", eqos->phy->speed); 909ba4dfef1SStephen Warren return -EINVAL; 910ba4dfef1SStephen Warren } 911ba4dfef1SStephen Warren 912ba4dfef1SStephen Warren ret = clk_set_rate(&eqos->clk_tx, rate); 913ba4dfef1SStephen Warren if (ret < 0) { 91490aa625cSMasahiro Yamada pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret); 915ba4dfef1SStephen Warren return ret; 916ba4dfef1SStephen Warren } 917ba4dfef1SStephen Warren 918ba4dfef1SStephen Warren return 0; 919ba4dfef1SStephen Warren } 920ba4dfef1SStephen Warren 9217a4c4eddSChristophe Roullier static int eqos_set_tx_clk_speed_stm32(struct udevice *dev) 9227a4c4eddSChristophe Roullier { 9237a4c4eddSChristophe Roullier return 0; 9247a4c4eddSChristophe Roullier } 9257a4c4eddSChristophe Roullier 926ba4dfef1SStephen Warren static int eqos_adjust_link(struct udevice *dev) 927ba4dfef1SStephen Warren { 928ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 929ba4dfef1SStephen Warren int ret; 930ba4dfef1SStephen Warren bool en_calibration; 931ba4dfef1SStephen Warren 932ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 933ba4dfef1SStephen Warren 934ba4dfef1SStephen Warren if (eqos->phy->duplex) 935ba4dfef1SStephen Warren ret = eqos_set_full_duplex(dev); 936ba4dfef1SStephen Warren else 937ba4dfef1SStephen Warren ret = eqos_set_half_duplex(dev); 938ba4dfef1SStephen Warren if (ret < 0) { 93990aa625cSMasahiro Yamada pr_err("eqos_set_*_duplex() failed: %d", ret); 940ba4dfef1SStephen Warren return ret; 941ba4dfef1SStephen Warren } 942ba4dfef1SStephen Warren 943ba4dfef1SStephen Warren switch (eqos->phy->speed) { 944ba4dfef1SStephen Warren case SPEED_1000: 945ba4dfef1SStephen Warren en_calibration = true; 946ba4dfef1SStephen Warren ret = eqos_set_gmii_speed(dev); 947ba4dfef1SStephen Warren break; 948ba4dfef1SStephen Warren case SPEED_100: 949ba4dfef1SStephen Warren en_calibration = true; 950ba4dfef1SStephen Warren ret = eqos_set_mii_speed_100(dev); 951ba4dfef1SStephen Warren break; 952ba4dfef1SStephen Warren case SPEED_10: 953ba4dfef1SStephen Warren en_calibration = false; 954ba4dfef1SStephen Warren ret = eqos_set_mii_speed_10(dev); 955ba4dfef1SStephen Warren break; 956ba4dfef1SStephen Warren default: 95790aa625cSMasahiro Yamada pr_err("invalid speed %d", eqos->phy->speed); 958ba4dfef1SStephen Warren return -EINVAL; 959ba4dfef1SStephen Warren } 960ba4dfef1SStephen Warren if (ret < 0) { 96190aa625cSMasahiro Yamada pr_err("eqos_set_*mii_speed*() failed: %d", ret); 962ba4dfef1SStephen Warren return ret; 963ba4dfef1SStephen Warren } 964ba4dfef1SStephen Warren 965ba4dfef1SStephen Warren if (en_calibration) { 9667a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_calibrate_pads(dev); 967ba4dfef1SStephen Warren if (ret < 0) { 9687a4c4eddSChristophe Roullier pr_err("eqos_calibrate_pads() failed: %d", 9697a4c4eddSChristophe Roullier ret); 970ba4dfef1SStephen Warren return ret; 971ba4dfef1SStephen Warren } 972ba4dfef1SStephen Warren } else { 9737a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_disable_calibration(dev); 974ba4dfef1SStephen Warren if (ret < 0) { 9757a4c4eddSChristophe Roullier pr_err("eqos_disable_calibration() failed: %d", 976ba4dfef1SStephen Warren ret); 977ba4dfef1SStephen Warren return ret; 978ba4dfef1SStephen Warren } 979ba4dfef1SStephen Warren } 9807a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_set_tx_clk_speed(dev); 981ba4dfef1SStephen Warren if (ret < 0) { 9827a4c4eddSChristophe Roullier pr_err("eqos_set_tx_clk_speed() failed: %d", ret); 983ba4dfef1SStephen Warren return ret; 984ba4dfef1SStephen Warren } 985ba4dfef1SStephen Warren 986ba4dfef1SStephen Warren return 0; 987ba4dfef1SStephen Warren } 988ba4dfef1SStephen Warren 989ba4dfef1SStephen Warren static int eqos_write_hwaddr(struct udevice *dev) 990ba4dfef1SStephen Warren { 991ba4dfef1SStephen Warren struct eth_pdata *plat = dev_get_platdata(dev); 992ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 993ba4dfef1SStephen Warren uint32_t val; 994ba4dfef1SStephen Warren 995ba4dfef1SStephen Warren /* 996ba4dfef1SStephen Warren * This function may be called before start() or after stop(). At that 997ba4dfef1SStephen Warren * time, on at least some configurations of the EQoS HW, all clocks to 998ba4dfef1SStephen Warren * the EQoS HW block will be stopped, and a reset signal applied. If 999ba4dfef1SStephen Warren * any register access is attempted in this state, bus timeouts or CPU 1000ba4dfef1SStephen Warren * hangs may occur. This check prevents that. 1001ba4dfef1SStephen Warren * 1002ba4dfef1SStephen Warren * A simple solution to this problem would be to not implement 1003ba4dfef1SStephen Warren * write_hwaddr(), since start() always writes the MAC address into HW 1004ba4dfef1SStephen Warren * anyway. However, it is desirable to implement write_hwaddr() to 1005ba4dfef1SStephen Warren * support the case of SW that runs subsequent to U-Boot which expects 1006ba4dfef1SStephen Warren * the MAC address to already be programmed into the EQoS registers, 1007ba4dfef1SStephen Warren * which must happen irrespective of whether the U-Boot user (or 1008ba4dfef1SStephen Warren * scripts) actually made use of the EQoS device, and hence 1009ba4dfef1SStephen Warren * irrespective of whether start() was ever called. 1010ba4dfef1SStephen Warren * 1011ba4dfef1SStephen Warren * Note that this requirement by subsequent SW is not valid for 1012ba4dfef1SStephen Warren * Tegra186, and is likely not valid for any non-PCI instantiation of 1013ba4dfef1SStephen Warren * the EQoS HW block. This function is implemented solely as 1014ba4dfef1SStephen Warren * future-proofing with the expectation the driver will eventually be 1015ba4dfef1SStephen Warren * ported to some system where the expectation above is true. 1016ba4dfef1SStephen Warren */ 1017ba4dfef1SStephen Warren if (!eqos->config->reg_access_always_ok && !eqos->reg_access_ok) 1018ba4dfef1SStephen Warren return 0; 1019ba4dfef1SStephen Warren 1020ba4dfef1SStephen Warren /* Update the MAC address */ 1021ba4dfef1SStephen Warren val = (plat->enetaddr[5] << 8) | 1022ba4dfef1SStephen Warren (plat->enetaddr[4]); 1023ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->address0_high); 1024ba4dfef1SStephen Warren val = (plat->enetaddr[3] << 24) | 1025ba4dfef1SStephen Warren (plat->enetaddr[2] << 16) | 1026ba4dfef1SStephen Warren (plat->enetaddr[1] << 8) | 1027ba4dfef1SStephen Warren (plat->enetaddr[0]); 1028ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->address0_low); 1029ba4dfef1SStephen Warren 1030ba4dfef1SStephen Warren return 0; 1031ba4dfef1SStephen Warren } 1032ba4dfef1SStephen Warren 1033ba4dfef1SStephen Warren static int eqos_start(struct udevice *dev) 1034ba4dfef1SStephen Warren { 1035ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1036ba4dfef1SStephen Warren int ret, i; 1037ba4dfef1SStephen Warren ulong rate; 1038ba4dfef1SStephen Warren u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl; 1039ba4dfef1SStephen Warren ulong last_rx_desc; 1040ba4dfef1SStephen Warren 1041ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1042ba4dfef1SStephen Warren 1043ba4dfef1SStephen Warren eqos->tx_desc_idx = 0; 1044ba4dfef1SStephen Warren eqos->rx_desc_idx = 0; 1045ba4dfef1SStephen Warren 10467a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_start_clks(dev); 1047ba4dfef1SStephen Warren if (ret < 0) { 10487a4c4eddSChristophe Roullier pr_err("eqos_start_clks() failed: %d", ret); 1049ba4dfef1SStephen Warren goto err; 1050ba4dfef1SStephen Warren } 1051ba4dfef1SStephen Warren 10527a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_start_resets(dev); 1053ba4dfef1SStephen Warren if (ret < 0) { 10547a4c4eddSChristophe Roullier pr_err("eqos_start_resets() failed: %d", ret); 1055ba4dfef1SStephen Warren goto err_stop_clks; 1056ba4dfef1SStephen Warren } 1057ba4dfef1SStephen Warren 1058ba4dfef1SStephen Warren udelay(10); 1059ba4dfef1SStephen Warren 1060ba4dfef1SStephen Warren eqos->reg_access_ok = true; 1061ba4dfef1SStephen Warren 1062b491b498SJon Lin ret = wait_for_bit_le32(&eqos->dma_regs->mode, 10637a4c4eddSChristophe Roullier EQOS_DMA_MODE_SWR, false, 10647a4c4eddSChristophe Roullier eqos->config->swr_wait, false); 1065ba4dfef1SStephen Warren if (ret) { 106690aa625cSMasahiro Yamada pr_err("EQOS_DMA_MODE_SWR stuck"); 1067ba4dfef1SStephen Warren goto err_stop_resets; 1068ba4dfef1SStephen Warren } 1069ba4dfef1SStephen Warren 10707a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_calibrate_pads(dev); 1071ba4dfef1SStephen Warren if (ret < 0) { 10727a4c4eddSChristophe Roullier pr_err("eqos_calibrate_pads() failed: %d", ret); 1073ba4dfef1SStephen Warren goto err_stop_resets; 1074ba4dfef1SStephen Warren } 10757a4c4eddSChristophe Roullier rate = eqos->config->ops->eqos_get_tick_clk_rate(dev); 1076ba4dfef1SStephen Warren 1077ba4dfef1SStephen Warren val = (rate / 1000000) - 1; 1078ba4dfef1SStephen Warren writel(val, &eqos->mac_regs->us_tic_counter); 1079ba4dfef1SStephen Warren 10807a4c4eddSChristophe Roullier /* 10817a4c4eddSChristophe Roullier * if PHY was already connected and configured, 10827a4c4eddSChristophe Roullier * don't need to reconnect/reconfigure again 10837a4c4eddSChristophe Roullier */ 10847a4c4eddSChristophe Roullier if (!eqos->phy) { 108583d31c08SPatrick Delaunay eqos->phy = phy_connect(eqos->mii, eqos->phyaddr, dev, 10867a4c4eddSChristophe Roullier eqos->config->interface(dev)); 1087ba4dfef1SStephen Warren if (!eqos->phy) { 108890aa625cSMasahiro Yamada pr_err("phy_connect() failed"); 1089ba4dfef1SStephen Warren goto err_stop_resets; 1090ba4dfef1SStephen Warren } 109183d31c08SPatrick Delaunay 109283d31c08SPatrick Delaunay if (eqos->max_speed) { 109383d31c08SPatrick Delaunay ret = phy_set_supported(eqos->phy, eqos->max_speed); 109483d31c08SPatrick Delaunay if (ret) { 109583d31c08SPatrick Delaunay pr_err("phy_set_supported() failed: %d", ret); 109683d31c08SPatrick Delaunay goto err_shutdown_phy; 109783d31c08SPatrick Delaunay } 109883d31c08SPatrick Delaunay } 109983d31c08SPatrick Delaunay 1100ba4dfef1SStephen Warren ret = phy_config(eqos->phy); 1101ba4dfef1SStephen Warren if (ret < 0) { 110290aa625cSMasahiro Yamada pr_err("phy_config() failed: %d", ret); 1103ba4dfef1SStephen Warren goto err_shutdown_phy; 1104ba4dfef1SStephen Warren } 11057a4c4eddSChristophe Roullier } 11067a4c4eddSChristophe Roullier 1107ba4dfef1SStephen Warren ret = phy_startup(eqos->phy); 1108ba4dfef1SStephen Warren if (ret < 0) { 110990aa625cSMasahiro Yamada pr_err("phy_startup() failed: %d", ret); 1110ba4dfef1SStephen Warren goto err_shutdown_phy; 1111ba4dfef1SStephen Warren } 1112ba4dfef1SStephen Warren 1113ba4dfef1SStephen Warren if (!eqos->phy->link) { 111490aa625cSMasahiro Yamada pr_err("No link"); 1115ba4dfef1SStephen Warren goto err_shutdown_phy; 1116ba4dfef1SStephen Warren } 1117ba4dfef1SStephen Warren 1118ba4dfef1SStephen Warren ret = eqos_adjust_link(dev); 1119ba4dfef1SStephen Warren if (ret < 0) { 112090aa625cSMasahiro Yamada pr_err("eqos_adjust_link() failed: %d", ret); 1121ba4dfef1SStephen Warren goto err_shutdown_phy; 1122ba4dfef1SStephen Warren } 1123ba4dfef1SStephen Warren 1124ba4dfef1SStephen Warren /* Configure MTL */ 1125ba4dfef1SStephen Warren 1126ba4dfef1SStephen Warren /* Enable Store and Forward mode for TX */ 1127ba4dfef1SStephen Warren /* Program Tx operating mode */ 1128ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->txq0_operation_mode, 1129ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TSF | 1130ba4dfef1SStephen Warren (EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED << 1131ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT)); 1132ba4dfef1SStephen Warren 1133ba4dfef1SStephen Warren /* Transmit Queue weight */ 1134ba4dfef1SStephen Warren writel(0x10, &eqos->mtl_regs->txq0_quantum_weight); 1135ba4dfef1SStephen Warren 1136ba4dfef1SStephen Warren /* Enable Store and Forward mode for RX, since no jumbo frame */ 1137ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1138ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RSF); 1139ba4dfef1SStephen Warren 1140ba4dfef1SStephen Warren /* Transmit/Receive queue fifo size; use all RAM for 1 queue */ 1141ba4dfef1SStephen Warren val = readl(&eqos->mac_regs->hw_feature1); 1142ba4dfef1SStephen Warren tx_fifo_sz = (val >> EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT) & 1143ba4dfef1SStephen Warren EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK; 1144ba4dfef1SStephen Warren rx_fifo_sz = (val >> EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT) & 1145ba4dfef1SStephen Warren EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK; 1146ba4dfef1SStephen Warren 1147ba4dfef1SStephen Warren /* 1148ba4dfef1SStephen Warren * r/tx_fifo_sz is encoded as log2(n / 128). Undo that by shifting. 1149ba4dfef1SStephen Warren * r/tqs is encoded as (n / 256) - 1. 1150ba4dfef1SStephen Warren */ 1151ba4dfef1SStephen Warren tqs = (128 << tx_fifo_sz) / 256 - 1; 1152ba4dfef1SStephen Warren rqs = (128 << rx_fifo_sz) / 256 - 1; 1153ba4dfef1SStephen Warren 1154ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mtl_regs->txq0_operation_mode, 1155ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TQS_MASK << 1156ba4dfef1SStephen Warren EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT, 1157ba4dfef1SStephen Warren tqs << EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT); 1158ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1159ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RQS_MASK << 1160ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT, 1161ba4dfef1SStephen Warren rqs << EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT); 1162ba4dfef1SStephen Warren 1163ba4dfef1SStephen Warren /* Flow control used only if each channel gets 4KB or more FIFO */ 1164ba4dfef1SStephen Warren if (rqs >= ((4096 / 256) - 1)) { 1165ba4dfef1SStephen Warren u32 rfd, rfa; 1166ba4dfef1SStephen Warren 1167ba4dfef1SStephen Warren setbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1168ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_EHFC); 1169ba4dfef1SStephen Warren 1170ba4dfef1SStephen Warren /* 1171ba4dfef1SStephen Warren * Set Threshold for Activating Flow Contol space for min 2 1172ba4dfef1SStephen Warren * frames ie, (1500 * 1) = 1500 bytes. 1173ba4dfef1SStephen Warren * 1174ba4dfef1SStephen Warren * Set Threshold for Deactivating Flow Contol for space of 1175ba4dfef1SStephen Warren * min 1 frame (frame size 1500bytes) in receive fifo 1176ba4dfef1SStephen Warren */ 1177ba4dfef1SStephen Warren if (rqs == ((4096 / 256) - 1)) { 1178ba4dfef1SStephen Warren /* 1179ba4dfef1SStephen Warren * This violates the above formula because of FIFO size 1180ba4dfef1SStephen Warren * limit therefore overflow may occur inspite of this. 1181ba4dfef1SStephen Warren */ 1182ba4dfef1SStephen Warren rfd = 0x3; /* Full-3K */ 1183ba4dfef1SStephen Warren rfa = 0x1; /* Full-1.5K */ 1184ba4dfef1SStephen Warren } else if (rqs == ((8192 / 256) - 1)) { 1185ba4dfef1SStephen Warren rfd = 0x6; /* Full-4K */ 1186ba4dfef1SStephen Warren rfa = 0xa; /* Full-6K */ 1187ba4dfef1SStephen Warren } else if (rqs == ((16384 / 256) - 1)) { 1188ba4dfef1SStephen Warren rfd = 0x6; /* Full-4K */ 1189ba4dfef1SStephen Warren rfa = 0x12; /* Full-10K */ 1190ba4dfef1SStephen Warren } else { 1191ba4dfef1SStephen Warren rfd = 0x6; /* Full-4K */ 1192ba4dfef1SStephen Warren rfa = 0x1E; /* Full-16K */ 1193ba4dfef1SStephen Warren } 1194ba4dfef1SStephen Warren 1195ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mtl_regs->rxq0_operation_mode, 1196ba4dfef1SStephen Warren (EQOS_MTL_RXQ0_OPERATION_MODE_RFD_MASK << 1197ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT) | 1198ba4dfef1SStephen Warren (EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK << 1199ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT), 1200ba4dfef1SStephen Warren (rfd << 1201ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT) | 1202ba4dfef1SStephen Warren (rfa << 1203ba4dfef1SStephen Warren EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT)); 1204ba4dfef1SStephen Warren } 1205ba4dfef1SStephen Warren 1206ba4dfef1SStephen Warren /* Configure MAC */ 1207ba4dfef1SStephen Warren 1208ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, 1209ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << 1210ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, 12117a4c4eddSChristophe Roullier eqos->config->config_mac << 1212ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); 1213ba4dfef1SStephen Warren 1214ba4dfef1SStephen Warren /* Set TX flow control parameters */ 1215ba4dfef1SStephen Warren /* Set Pause Time */ 1216ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl, 1217ba4dfef1SStephen Warren 0xffff << EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT); 1218ba4dfef1SStephen Warren /* Assign priority for TX flow control */ 1219ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->txq_prty_map0, 1220ba4dfef1SStephen Warren EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK << 1221ba4dfef1SStephen Warren EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_SHIFT); 1222ba4dfef1SStephen Warren /* Assign priority for RX flow control */ 1223ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->rxq_ctrl2, 1224ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK << 1225ba4dfef1SStephen Warren EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT); 1226ba4dfef1SStephen Warren /* Enable flow control */ 1227ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl, 1228ba4dfef1SStephen Warren EQOS_MAC_Q0_TX_FLOW_CTRL_TFE); 1229ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->rx_flow_ctrl, 1230ba4dfef1SStephen Warren EQOS_MAC_RX_FLOW_CTRL_RFE); 1231ba4dfef1SStephen Warren 1232ba4dfef1SStephen Warren clrsetbits_le32(&eqos->mac_regs->configuration, 1233ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_GPSLCE | 1234ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_WD | 1235ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_JD | 1236ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_JE, 1237ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_CST | 1238ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_ACS); 1239ba4dfef1SStephen Warren 1240ba4dfef1SStephen Warren eqos_write_hwaddr(dev); 1241ba4dfef1SStephen Warren 1242ba4dfef1SStephen Warren /* Configure DMA */ 1243ba4dfef1SStephen Warren 1244ba4dfef1SStephen Warren /* Enable OSP mode */ 1245ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_tx_control, 1246ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_OSP); 1247ba4dfef1SStephen Warren 1248ba4dfef1SStephen Warren /* RX buffer size. Must be a multiple of bus width */ 1249ba4dfef1SStephen Warren clrsetbits_le32(&eqos->dma_regs->ch0_rx_control, 1250ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RBSZ_MASK << 1251ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT, 1252ba4dfef1SStephen Warren EQOS_MAX_PACKET_SIZE << 1253ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT); 1254ba4dfef1SStephen Warren 1255ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_control, 1256ba4dfef1SStephen Warren EQOS_DMA_CH0_CONTROL_PBLX8); 1257ba4dfef1SStephen Warren 1258ba4dfef1SStephen Warren /* 1259ba4dfef1SStephen Warren * Burst length must be < 1/2 FIFO size. 1260ba4dfef1SStephen Warren * FIFO size in tqs is encoded as (n / 256) - 1. 1261ba4dfef1SStephen Warren * Each burst is n * 8 (PBLX8) * 16 (AXI width) == 128 bytes. 1262ba4dfef1SStephen Warren * Half of n * 256 is n * 128, so pbl == tqs, modulo the -1. 1263ba4dfef1SStephen Warren */ 1264ba4dfef1SStephen Warren pbl = tqs + 1; 1265ba4dfef1SStephen Warren if (pbl > 32) 1266ba4dfef1SStephen Warren pbl = 32; 1267ba4dfef1SStephen Warren clrsetbits_le32(&eqos->dma_regs->ch0_tx_control, 1268ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_TXPBL_MASK << 1269ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT, 1270ba4dfef1SStephen Warren pbl << EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT); 1271ba4dfef1SStephen Warren 1272ba4dfef1SStephen Warren clrsetbits_le32(&eqos->dma_regs->ch0_rx_control, 1273ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RXPBL_MASK << 1274ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT, 1275ba4dfef1SStephen Warren 8 << EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT); 1276ba4dfef1SStephen Warren 1277ba4dfef1SStephen Warren /* DMA performance configuration */ 1278ba4dfef1SStephen Warren val = (2 << EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT) | 1279ba4dfef1SStephen Warren EQOS_DMA_SYSBUS_MODE_EAME | EQOS_DMA_SYSBUS_MODE_BLEN16 | 1280ba4dfef1SStephen Warren EQOS_DMA_SYSBUS_MODE_BLEN8 | EQOS_DMA_SYSBUS_MODE_BLEN4; 1281ba4dfef1SStephen Warren writel(val, &eqos->dma_regs->sysbus_mode); 1282ba4dfef1SStephen Warren 1283ba4dfef1SStephen Warren /* Set up descriptors */ 1284ba4dfef1SStephen Warren 1285ba4dfef1SStephen Warren memset(eqos->descs, 0, EQOS_DESCRIPTORS_SIZE); 1286ba4dfef1SStephen Warren for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) { 1287ba4dfef1SStephen Warren struct eqos_desc *rx_desc = &(eqos->rx_descs[i]); 1288ba4dfef1SStephen Warren rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + 1289ba4dfef1SStephen Warren (i * EQOS_MAX_PACKET_SIZE)); 12906143c348SMarek Vasut rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; 12916399c699SMarek Vasut eqos->config->ops->eqos_flush_desc(rx_desc); 1292ba4dfef1SStephen Warren } 1293ba4dfef1SStephen Warren 1294ba4dfef1SStephen Warren writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); 1295ba4dfef1SStephen Warren writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address); 1296ba4dfef1SStephen Warren writel(EQOS_DESCRIPTORS_TX - 1, 1297ba4dfef1SStephen Warren &eqos->dma_regs->ch0_txdesc_ring_length); 1298ba4dfef1SStephen Warren 1299ba4dfef1SStephen Warren writel(0, &eqos->dma_regs->ch0_rxdesc_list_haddress); 1300ba4dfef1SStephen Warren writel((ulong)eqos->rx_descs, &eqos->dma_regs->ch0_rxdesc_list_address); 1301ba4dfef1SStephen Warren writel(EQOS_DESCRIPTORS_RX - 1, 1302ba4dfef1SStephen Warren &eqos->dma_regs->ch0_rxdesc_ring_length); 1303ba4dfef1SStephen Warren 1304ba4dfef1SStephen Warren /* Enable everything */ 1305ba4dfef1SStephen Warren 1306ba4dfef1SStephen Warren setbits_le32(&eqos->mac_regs->configuration, 1307ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE); 1308ba4dfef1SStephen Warren 1309ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_tx_control, 1310ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_ST); 1311ba4dfef1SStephen Warren setbits_le32(&eqos->dma_regs->ch0_rx_control, 1312ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_SR); 1313ba4dfef1SStephen Warren 1314ba4dfef1SStephen Warren /* TX tail pointer not written until we need to TX a packet */ 1315ba4dfef1SStephen Warren /* 1316ba4dfef1SStephen Warren * Point RX tail pointer at last descriptor. Ideally, we'd point at the 1317ba4dfef1SStephen Warren * first descriptor, implying all descriptors were available. However, 1318ba4dfef1SStephen Warren * that's not distinguishable from none of the descriptors being 1319ba4dfef1SStephen Warren * available. 1320ba4dfef1SStephen Warren */ 1321ba4dfef1SStephen Warren last_rx_desc = (ulong)&(eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)]); 1322ba4dfef1SStephen Warren writel(last_rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); 1323ba4dfef1SStephen Warren 1324ba4dfef1SStephen Warren eqos->started = true; 1325ba4dfef1SStephen Warren 1326ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1327ba4dfef1SStephen Warren return 0; 1328ba4dfef1SStephen Warren 1329ba4dfef1SStephen Warren err_shutdown_phy: 1330ba4dfef1SStephen Warren phy_shutdown(eqos->phy); 1331ba4dfef1SStephen Warren err_stop_resets: 13327a4c4eddSChristophe Roullier eqos->config->ops->eqos_stop_resets(dev); 1333ba4dfef1SStephen Warren err_stop_clks: 13347a4c4eddSChristophe Roullier eqos->config->ops->eqos_stop_clks(dev); 1335ba4dfef1SStephen Warren err: 133690aa625cSMasahiro Yamada pr_err("FAILED: %d", ret); 1337ba4dfef1SStephen Warren return ret; 1338ba4dfef1SStephen Warren } 1339ba4dfef1SStephen Warren 13408aaada72SPatrick Delaunay static void eqos_stop(struct udevice *dev) 1341ba4dfef1SStephen Warren { 1342ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1343ba4dfef1SStephen Warren int i; 1344ba4dfef1SStephen Warren 1345ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1346ba4dfef1SStephen Warren 1347ba4dfef1SStephen Warren if (!eqos->started) 1348ba4dfef1SStephen Warren return; 1349ba4dfef1SStephen Warren eqos->started = false; 1350ba4dfef1SStephen Warren eqos->reg_access_ok = false; 1351ba4dfef1SStephen Warren 1352ba4dfef1SStephen Warren /* Disable TX DMA */ 1353ba4dfef1SStephen Warren clrbits_le32(&eqos->dma_regs->ch0_tx_control, 1354ba4dfef1SStephen Warren EQOS_DMA_CH0_TX_CONTROL_ST); 1355ba4dfef1SStephen Warren 1356ba4dfef1SStephen Warren /* Wait for TX all packets to drain out of MTL */ 1357ba4dfef1SStephen Warren for (i = 0; i < 1000000; i++) { 1358ba4dfef1SStephen Warren u32 val = readl(&eqos->mtl_regs->txq0_debug); 1359ba4dfef1SStephen Warren u32 trcsts = (val >> EQOS_MTL_TXQ0_DEBUG_TRCSTS_SHIFT) & 1360ba4dfef1SStephen Warren EQOS_MTL_TXQ0_DEBUG_TRCSTS_MASK; 1361ba4dfef1SStephen Warren u32 txqsts = val & EQOS_MTL_TXQ0_DEBUG_TXQSTS; 1362ba4dfef1SStephen Warren if ((trcsts != 1) && (!txqsts)) 1363ba4dfef1SStephen Warren break; 1364ba4dfef1SStephen Warren } 1365ba4dfef1SStephen Warren 1366ba4dfef1SStephen Warren /* Turn off MAC TX and RX */ 1367ba4dfef1SStephen Warren clrbits_le32(&eqos->mac_regs->configuration, 1368ba4dfef1SStephen Warren EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE); 1369ba4dfef1SStephen Warren 1370ba4dfef1SStephen Warren /* Wait for all RX packets to drain out of MTL */ 1371ba4dfef1SStephen Warren for (i = 0; i < 1000000; i++) { 1372ba4dfef1SStephen Warren u32 val = readl(&eqos->mtl_regs->rxq0_debug); 1373ba4dfef1SStephen Warren u32 prxq = (val >> EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT) & 1374ba4dfef1SStephen Warren EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK; 1375ba4dfef1SStephen Warren u32 rxqsts = (val >> EQOS_MTL_RXQ0_DEBUG_RXQSTS_SHIFT) & 1376ba4dfef1SStephen Warren EQOS_MTL_RXQ0_DEBUG_RXQSTS_MASK; 1377ba4dfef1SStephen Warren if ((!prxq) && (!rxqsts)) 1378ba4dfef1SStephen Warren break; 1379ba4dfef1SStephen Warren } 1380ba4dfef1SStephen Warren 1381ba4dfef1SStephen Warren /* Turn off RX DMA */ 1382ba4dfef1SStephen Warren clrbits_le32(&eqos->dma_regs->ch0_rx_control, 1383ba4dfef1SStephen Warren EQOS_DMA_CH0_RX_CONTROL_SR); 1384ba4dfef1SStephen Warren 1385ba4dfef1SStephen Warren if (eqos->phy) { 1386ba4dfef1SStephen Warren phy_shutdown(eqos->phy); 1387ba4dfef1SStephen Warren } 13887a4c4eddSChristophe Roullier eqos->config->ops->eqos_stop_resets(dev); 13897a4c4eddSChristophe Roullier eqos->config->ops->eqos_stop_clks(dev); 1390ba4dfef1SStephen Warren 1391ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1392ba4dfef1SStephen Warren } 1393ba4dfef1SStephen Warren 13948aaada72SPatrick Delaunay static int eqos_send(struct udevice *dev, void *packet, int length) 1395ba4dfef1SStephen Warren { 1396ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1397ba4dfef1SStephen Warren struct eqos_desc *tx_desc; 1398ba4dfef1SStephen Warren int i; 1399ba4dfef1SStephen Warren 1400ba4dfef1SStephen Warren debug("%s(dev=%p, packet=%p, length=%d):\n", __func__, dev, packet, 1401ba4dfef1SStephen Warren length); 1402ba4dfef1SStephen Warren 1403ba4dfef1SStephen Warren memcpy(eqos->tx_dma_buf, packet, length); 14047a4c4eddSChristophe Roullier eqos->config->ops->eqos_flush_buffer(eqos->tx_dma_buf, length); 1405ba4dfef1SStephen Warren 1406ba4dfef1SStephen Warren tx_desc = &(eqos->tx_descs[eqos->tx_desc_idx]); 1407ba4dfef1SStephen Warren eqos->tx_desc_idx++; 1408ba4dfef1SStephen Warren eqos->tx_desc_idx %= EQOS_DESCRIPTORS_TX; 1409ba4dfef1SStephen Warren 1410ba4dfef1SStephen Warren tx_desc->des0 = (ulong)eqos->tx_dma_buf; 1411ba4dfef1SStephen Warren tx_desc->des1 = 0; 1412ba4dfef1SStephen Warren tx_desc->des2 = length; 1413ba4dfef1SStephen Warren /* 1414ba4dfef1SStephen Warren * Make sure that if HW sees the _OWN write below, it will see all the 1415ba4dfef1SStephen Warren * writes to the rest of the descriptor too. 1416ba4dfef1SStephen Warren */ 1417ba4dfef1SStephen Warren mb(); 1418ba4dfef1SStephen Warren tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length; 14197a4c4eddSChristophe Roullier eqos->config->ops->eqos_flush_desc(tx_desc); 1420ba4dfef1SStephen Warren 1421364f8fdcSMarek Vasut writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])), 1422364f8fdcSMarek Vasut &eqos->dma_regs->ch0_txdesc_tail_pointer); 1423ba4dfef1SStephen Warren 1424ba4dfef1SStephen Warren for (i = 0; i < 1000000; i++) { 14257a4c4eddSChristophe Roullier eqos->config->ops->eqos_inval_desc(tx_desc); 1426ba4dfef1SStephen Warren if (!(readl(&tx_desc->des3) & EQOS_DESC3_OWN)) 1427ba4dfef1SStephen Warren return 0; 1428ba4dfef1SStephen Warren udelay(1); 1429ba4dfef1SStephen Warren } 1430ba4dfef1SStephen Warren 1431ba4dfef1SStephen Warren debug("%s: TX timeout\n", __func__); 1432ba4dfef1SStephen Warren 1433ba4dfef1SStephen Warren return -ETIMEDOUT; 1434ba4dfef1SStephen Warren } 1435ba4dfef1SStephen Warren 14368aaada72SPatrick Delaunay static int eqos_recv(struct udevice *dev, int flags, uchar **packetp) 1437ba4dfef1SStephen Warren { 1438ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1439ba4dfef1SStephen Warren struct eqos_desc *rx_desc; 1440ba4dfef1SStephen Warren int length; 1441ba4dfef1SStephen Warren 1442ba4dfef1SStephen Warren debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags); 1443ba4dfef1SStephen Warren 1444ba4dfef1SStephen Warren rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); 1445*865fce80SMarek Vasut eqos->config->ops->eqos_inval_desc(rx_desc); 1446ba4dfef1SStephen Warren if (rx_desc->des3 & EQOS_DESC3_OWN) { 1447ba4dfef1SStephen Warren debug("%s: RX packet not available\n", __func__); 1448ba4dfef1SStephen Warren return -EAGAIN; 1449ba4dfef1SStephen Warren } 1450ba4dfef1SStephen Warren 1451ba4dfef1SStephen Warren *packetp = eqos->rx_dma_buf + 1452ba4dfef1SStephen Warren (eqos->rx_desc_idx * EQOS_MAX_PACKET_SIZE); 1453ba4dfef1SStephen Warren length = rx_desc->des3 & 0x7fff; 1454ba4dfef1SStephen Warren debug("%s: *packetp=%p, length=%d\n", __func__, *packetp, length); 1455ba4dfef1SStephen Warren 14567a4c4eddSChristophe Roullier eqos->config->ops->eqos_inval_buffer(*packetp, length); 1457ba4dfef1SStephen Warren 1458ba4dfef1SStephen Warren return length; 1459ba4dfef1SStephen Warren } 1460ba4dfef1SStephen Warren 14618aaada72SPatrick Delaunay static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) 1462ba4dfef1SStephen Warren { 1463ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1464ba4dfef1SStephen Warren uchar *packet_expected; 1465ba4dfef1SStephen Warren struct eqos_desc *rx_desc; 1466ba4dfef1SStephen Warren 1467ba4dfef1SStephen Warren debug("%s(packet=%p, length=%d)\n", __func__, packet, length); 1468ba4dfef1SStephen Warren 1469ba4dfef1SStephen Warren packet_expected = eqos->rx_dma_buf + 1470ba4dfef1SStephen Warren (eqos->rx_desc_idx * EQOS_MAX_PACKET_SIZE); 1471ba4dfef1SStephen Warren if (packet != packet_expected) { 1472ba4dfef1SStephen Warren debug("%s: Unexpected packet (expected %p)\n", __func__, 1473ba4dfef1SStephen Warren packet_expected); 1474ba4dfef1SStephen Warren return -EINVAL; 1475ba4dfef1SStephen Warren } 1476ba4dfef1SStephen Warren 1477ba4dfef1SStephen Warren rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); 1478ba4dfef1SStephen Warren rx_desc->des0 = (u32)(ulong)packet; 1479ba4dfef1SStephen Warren rx_desc->des1 = 0; 1480ba4dfef1SStephen Warren rx_desc->des2 = 0; 1481ba4dfef1SStephen Warren /* 1482ba4dfef1SStephen Warren * Make sure that if HW sees the _OWN write below, it will see all the 1483ba4dfef1SStephen Warren * writes to the rest of the descriptor too. 1484ba4dfef1SStephen Warren */ 1485ba4dfef1SStephen Warren mb(); 14866143c348SMarek Vasut rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; 14877a4c4eddSChristophe Roullier eqos->config->ops->eqos_flush_desc(rx_desc); 1488ba4dfef1SStephen Warren 1489ba4dfef1SStephen Warren writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); 1490ba4dfef1SStephen Warren 1491ba4dfef1SStephen Warren eqos->rx_desc_idx++; 1492ba4dfef1SStephen Warren eqos->rx_desc_idx %= EQOS_DESCRIPTORS_RX; 1493ba4dfef1SStephen Warren 1494ba4dfef1SStephen Warren return 0; 1495ba4dfef1SStephen Warren } 1496ba4dfef1SStephen Warren 1497ba4dfef1SStephen Warren static int eqos_probe_resources_core(struct udevice *dev) 1498ba4dfef1SStephen Warren { 1499ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1500ba4dfef1SStephen Warren int ret; 1501ba4dfef1SStephen Warren 1502ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1503ba4dfef1SStephen Warren 1504ba4dfef1SStephen Warren eqos->descs = eqos_alloc_descs(EQOS_DESCRIPTORS_TX + 1505ba4dfef1SStephen Warren EQOS_DESCRIPTORS_RX); 1506ba4dfef1SStephen Warren if (!eqos->descs) { 1507ba4dfef1SStephen Warren debug("%s: eqos_alloc_descs() failed\n", __func__); 1508ba4dfef1SStephen Warren ret = -ENOMEM; 1509ba4dfef1SStephen Warren goto err; 1510ba4dfef1SStephen Warren } 1511ba4dfef1SStephen Warren eqos->tx_descs = (struct eqos_desc *)eqos->descs; 1512ba4dfef1SStephen Warren eqos->rx_descs = (eqos->tx_descs + EQOS_DESCRIPTORS_TX); 1513ba4dfef1SStephen Warren debug("%s: tx_descs=%p, rx_descs=%p\n", __func__, eqos->tx_descs, 1514ba4dfef1SStephen Warren eqos->rx_descs); 1515ba4dfef1SStephen Warren 1516ba4dfef1SStephen Warren eqos->tx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_MAX_PACKET_SIZE); 1517ba4dfef1SStephen Warren if (!eqos->tx_dma_buf) { 1518ba4dfef1SStephen Warren debug("%s: memalign(tx_dma_buf) failed\n", __func__); 1519ba4dfef1SStephen Warren ret = -ENOMEM; 1520ba4dfef1SStephen Warren goto err_free_descs; 1521ba4dfef1SStephen Warren } 15227a4c4eddSChristophe Roullier debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); 1523ba4dfef1SStephen Warren 1524ba4dfef1SStephen Warren eqos->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_RX_BUFFER_SIZE); 1525ba4dfef1SStephen Warren if (!eqos->rx_dma_buf) { 1526ba4dfef1SStephen Warren debug("%s: memalign(rx_dma_buf) failed\n", __func__); 1527ba4dfef1SStephen Warren ret = -ENOMEM; 1528ba4dfef1SStephen Warren goto err_free_tx_dma_buf; 1529ba4dfef1SStephen Warren } 15307a4c4eddSChristophe Roullier debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); 1531ba4dfef1SStephen Warren 1532ba4dfef1SStephen Warren eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE); 1533ba4dfef1SStephen Warren if (!eqos->rx_pkt) { 1534ba4dfef1SStephen Warren debug("%s: malloc(rx_pkt) failed\n", __func__); 1535ba4dfef1SStephen Warren ret = -ENOMEM; 1536ba4dfef1SStephen Warren goto err_free_rx_dma_buf; 1537ba4dfef1SStephen Warren } 1538ba4dfef1SStephen Warren debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt); 1539ba4dfef1SStephen Warren 1540ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1541ba4dfef1SStephen Warren return 0; 1542ba4dfef1SStephen Warren 1543ba4dfef1SStephen Warren err_free_rx_dma_buf: 1544ba4dfef1SStephen Warren free(eqos->rx_dma_buf); 1545ba4dfef1SStephen Warren err_free_tx_dma_buf: 1546ba4dfef1SStephen Warren free(eqos->tx_dma_buf); 1547ba4dfef1SStephen Warren err_free_descs: 1548ba4dfef1SStephen Warren eqos_free_descs(eqos->descs); 1549ba4dfef1SStephen Warren err: 1550ba4dfef1SStephen Warren 1551ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 1552ba4dfef1SStephen Warren return ret; 1553ba4dfef1SStephen Warren } 1554ba4dfef1SStephen Warren 1555ba4dfef1SStephen Warren static int eqos_remove_resources_core(struct udevice *dev) 1556ba4dfef1SStephen Warren { 1557ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1558ba4dfef1SStephen Warren 1559ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1560ba4dfef1SStephen Warren 1561ba4dfef1SStephen Warren free(eqos->rx_pkt); 1562ba4dfef1SStephen Warren free(eqos->rx_dma_buf); 1563ba4dfef1SStephen Warren free(eqos->tx_dma_buf); 1564ba4dfef1SStephen Warren eqos_free_descs(eqos->descs); 1565ba4dfef1SStephen Warren 1566ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1567ba4dfef1SStephen Warren return 0; 1568ba4dfef1SStephen Warren } 1569ba4dfef1SStephen Warren 1570ba4dfef1SStephen Warren static int eqos_probe_resources_tegra186(struct udevice *dev) 1571ba4dfef1SStephen Warren { 1572ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1573ba4dfef1SStephen Warren int ret; 1574ba4dfef1SStephen Warren 1575ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1576ba4dfef1SStephen Warren 1577ba4dfef1SStephen Warren ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl); 1578ba4dfef1SStephen Warren if (ret) { 157990aa625cSMasahiro Yamada pr_err("reset_get_by_name(rst) failed: %d", ret); 1580ba4dfef1SStephen Warren return ret; 1581ba4dfef1SStephen Warren } 1582ba4dfef1SStephen Warren 1583ba4dfef1SStephen Warren ret = gpio_request_by_name(dev, "phy-reset-gpios", 0, 1584ba4dfef1SStephen Warren &eqos->phy_reset_gpio, 1585ba4dfef1SStephen Warren GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 1586ba4dfef1SStephen Warren if (ret) { 158790aa625cSMasahiro Yamada pr_err("gpio_request_by_name(phy reset) failed: %d", ret); 1588ba4dfef1SStephen Warren goto err_free_reset_eqos; 1589ba4dfef1SStephen Warren } 1590ba4dfef1SStephen Warren 1591ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "slave_bus", &eqos->clk_slave_bus); 1592ba4dfef1SStephen Warren if (ret) { 159390aa625cSMasahiro Yamada pr_err("clk_get_by_name(slave_bus) failed: %d", ret); 1594ba4dfef1SStephen Warren goto err_free_gpio_phy_reset; 1595ba4dfef1SStephen Warren } 1596ba4dfef1SStephen Warren 1597ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "master_bus", &eqos->clk_master_bus); 1598ba4dfef1SStephen Warren if (ret) { 159990aa625cSMasahiro Yamada pr_err("clk_get_by_name(master_bus) failed: %d", ret); 1600ba4dfef1SStephen Warren goto err_free_clk_slave_bus; 1601ba4dfef1SStephen Warren } 1602ba4dfef1SStephen Warren 1603ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "rx", &eqos->clk_rx); 1604ba4dfef1SStephen Warren if (ret) { 160590aa625cSMasahiro Yamada pr_err("clk_get_by_name(rx) failed: %d", ret); 1606ba4dfef1SStephen Warren goto err_free_clk_master_bus; 1607ba4dfef1SStephen Warren } 1608ba4dfef1SStephen Warren 1609ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); 1610ba4dfef1SStephen Warren if (ret) { 161190aa625cSMasahiro Yamada pr_err("clk_get_by_name(ptp_ref) failed: %d", ret); 1612ba4dfef1SStephen Warren goto err_free_clk_rx; 1613ba4dfef1SStephen Warren return ret; 1614ba4dfef1SStephen Warren } 1615ba4dfef1SStephen Warren 1616ba4dfef1SStephen Warren ret = clk_get_by_name(dev, "tx", &eqos->clk_tx); 1617ba4dfef1SStephen Warren if (ret) { 161890aa625cSMasahiro Yamada pr_err("clk_get_by_name(tx) failed: %d", ret); 1619ba4dfef1SStephen Warren goto err_free_clk_ptp_ref; 1620ba4dfef1SStephen Warren } 1621ba4dfef1SStephen Warren 1622ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1623ba4dfef1SStephen Warren return 0; 1624ba4dfef1SStephen Warren 1625ba4dfef1SStephen Warren err_free_clk_ptp_ref: 1626ba4dfef1SStephen Warren clk_free(&eqos->clk_ptp_ref); 1627ba4dfef1SStephen Warren err_free_clk_rx: 1628ba4dfef1SStephen Warren clk_free(&eqos->clk_rx); 1629ba4dfef1SStephen Warren err_free_clk_master_bus: 1630ba4dfef1SStephen Warren clk_free(&eqos->clk_master_bus); 1631ba4dfef1SStephen Warren err_free_clk_slave_bus: 1632ba4dfef1SStephen Warren clk_free(&eqos->clk_slave_bus); 1633ba4dfef1SStephen Warren err_free_gpio_phy_reset: 1634ba4dfef1SStephen Warren dm_gpio_free(dev, &eqos->phy_reset_gpio); 1635ba4dfef1SStephen Warren err_free_reset_eqos: 1636ba4dfef1SStephen Warren reset_free(&eqos->reset_ctl); 1637ba4dfef1SStephen Warren 1638ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 1639ba4dfef1SStephen Warren return ret; 1640ba4dfef1SStephen Warren } 1641ba4dfef1SStephen Warren 16427a4c4eddSChristophe Roullier /* board-specific Ethernet Interface initializations. */ 16431e8d5d80SPatrick Delaunay __weak int board_interface_eth_init(struct udevice *dev, 16441e8d5d80SPatrick Delaunay phy_interface_t interface_type) 16457a4c4eddSChristophe Roullier { 16467a4c4eddSChristophe Roullier return 0; 16477a4c4eddSChristophe Roullier } 16487a4c4eddSChristophe Roullier 16497a4c4eddSChristophe Roullier static int eqos_probe_resources_stm32(struct udevice *dev) 16507a4c4eddSChristophe Roullier { 16517a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 16527a4c4eddSChristophe Roullier int ret; 16537a4c4eddSChristophe Roullier phy_interface_t interface; 16545bd3c538SChristophe Roullier struct ofnode_phandle_args phandle_args; 16557a4c4eddSChristophe Roullier 16567a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 16577a4c4eddSChristophe Roullier 16587a4c4eddSChristophe Roullier interface = eqos->config->interface(dev); 16597a4c4eddSChristophe Roullier 16607a4c4eddSChristophe Roullier if (interface == PHY_INTERFACE_MODE_NONE) { 16617a4c4eddSChristophe Roullier pr_err("Invalid PHY interface\n"); 16627a4c4eddSChristophe Roullier return -EINVAL; 16637a4c4eddSChristophe Roullier } 16647a4c4eddSChristophe Roullier 16651e8d5d80SPatrick Delaunay ret = board_interface_eth_init(dev, interface); 16667a4c4eddSChristophe Roullier if (ret) 16677a4c4eddSChristophe Roullier return -EINVAL; 16687a4c4eddSChristophe Roullier 166983d31c08SPatrick Delaunay eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); 167083d31c08SPatrick Delaunay 16717a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); 16727a4c4eddSChristophe Roullier if (ret) { 16737a4c4eddSChristophe Roullier pr_err("clk_get_by_name(master_bus) failed: %d", ret); 16747a4c4eddSChristophe Roullier goto err_probe; 16757a4c4eddSChristophe Roullier } 16767a4c4eddSChristophe Roullier 16777a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx); 16787a4c4eddSChristophe Roullier if (ret) { 16797a4c4eddSChristophe Roullier pr_err("clk_get_by_name(rx) failed: %d", ret); 16807a4c4eddSChristophe Roullier goto err_free_clk_master_bus; 16817a4c4eddSChristophe Roullier } 16827a4c4eddSChristophe Roullier 16837a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx); 16847a4c4eddSChristophe Roullier if (ret) { 16857a4c4eddSChristophe Roullier pr_err("clk_get_by_name(tx) failed: %d", ret); 16867a4c4eddSChristophe Roullier goto err_free_clk_rx; 16877a4c4eddSChristophe Roullier } 16887a4c4eddSChristophe Roullier 16897a4c4eddSChristophe Roullier /* Get ETH_CLK clocks (optional) */ 16907a4c4eddSChristophe Roullier ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck); 16917a4c4eddSChristophe Roullier if (ret) 16927a4c4eddSChristophe Roullier pr_warn("No phy clock provided %d", ret); 16937a4c4eddSChristophe Roullier 169483d31c08SPatrick Delaunay eqos->phyaddr = -1; 16955bd3c538SChristophe Roullier ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, 16965bd3c538SChristophe Roullier &phandle_args); 16975bd3c538SChristophe Roullier if (!ret) { 16985bd3c538SChristophe Roullier /* search "reset-gpios" in phy node */ 16995bd3c538SChristophe Roullier ret = gpio_request_by_name_nodev(phandle_args.node, 17005bd3c538SChristophe Roullier "reset-gpios", 0, 17015bd3c538SChristophe Roullier &eqos->phy_reset_gpio, 17025bd3c538SChristophe Roullier GPIOD_IS_OUT | 17035bd3c538SChristophe Roullier GPIOD_IS_OUT_ACTIVE); 17045bd3c538SChristophe Roullier if (ret) 17055bd3c538SChristophe Roullier pr_warn("gpio_request_by_name(phy reset) not provided %d", 17065bd3c538SChristophe Roullier ret); 170783d31c08SPatrick Delaunay 170883d31c08SPatrick Delaunay eqos->phyaddr = ofnode_read_u32_default(phandle_args.node, 170983d31c08SPatrick Delaunay "reg", -1); 17105bd3c538SChristophe Roullier } 17115bd3c538SChristophe Roullier 17127a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 17137a4c4eddSChristophe Roullier return 0; 17147a4c4eddSChristophe Roullier 17157a4c4eddSChristophe Roullier err_free_clk_rx: 17167a4c4eddSChristophe Roullier clk_free(&eqos->clk_rx); 17177a4c4eddSChristophe Roullier err_free_clk_master_bus: 17187a4c4eddSChristophe Roullier clk_free(&eqos->clk_master_bus); 17197a4c4eddSChristophe Roullier err_probe: 17207a4c4eddSChristophe Roullier 17217a4c4eddSChristophe Roullier debug("%s: returns %d\n", __func__, ret); 17227a4c4eddSChristophe Roullier return ret; 17237a4c4eddSChristophe Roullier } 17247a4c4eddSChristophe Roullier 17257a4c4eddSChristophe Roullier static phy_interface_t eqos_get_interface_stm32(struct udevice *dev) 17267a4c4eddSChristophe Roullier { 17277a4c4eddSChristophe Roullier const char *phy_mode; 17287a4c4eddSChristophe Roullier phy_interface_t interface = PHY_INTERFACE_MODE_NONE; 17297a4c4eddSChristophe Roullier 17307a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 17317a4c4eddSChristophe Roullier 17327a4c4eddSChristophe Roullier phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", 17337a4c4eddSChristophe Roullier NULL); 17347a4c4eddSChristophe Roullier if (phy_mode) 17357a4c4eddSChristophe Roullier interface = phy_get_interface_by_name(phy_mode); 17367a4c4eddSChristophe Roullier 17377a4c4eddSChristophe Roullier return interface; 17387a4c4eddSChristophe Roullier } 17397a4c4eddSChristophe Roullier 17407a4c4eddSChristophe Roullier static phy_interface_t eqos_get_interface_tegra186(struct udevice *dev) 17417a4c4eddSChristophe Roullier { 17427a4c4eddSChristophe Roullier return PHY_INTERFACE_MODE_MII; 17437a4c4eddSChristophe Roullier } 17447a4c4eddSChristophe Roullier 1745ba4dfef1SStephen Warren static int eqos_remove_resources_tegra186(struct udevice *dev) 1746ba4dfef1SStephen Warren { 1747ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1748ba4dfef1SStephen Warren 1749ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1750ba4dfef1SStephen Warren 1751ba4dfef1SStephen Warren clk_free(&eqos->clk_tx); 1752ba4dfef1SStephen Warren clk_free(&eqos->clk_ptp_ref); 1753ba4dfef1SStephen Warren clk_free(&eqos->clk_rx); 1754ba4dfef1SStephen Warren clk_free(&eqos->clk_slave_bus); 1755ba4dfef1SStephen Warren clk_free(&eqos->clk_master_bus); 1756ba4dfef1SStephen Warren dm_gpio_free(dev, &eqos->phy_reset_gpio); 1757ba4dfef1SStephen Warren reset_free(&eqos->reset_ctl); 1758ba4dfef1SStephen Warren 1759ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1760ba4dfef1SStephen Warren return 0; 1761ba4dfef1SStephen Warren } 1762ba4dfef1SStephen Warren 17637a4c4eddSChristophe Roullier static int eqos_remove_resources_stm32(struct udevice *dev) 17647a4c4eddSChristophe Roullier { 17657a4c4eddSChristophe Roullier struct eqos_priv *eqos = dev_get_priv(dev); 17667a4c4eddSChristophe Roullier 17677a4c4eddSChristophe Roullier debug("%s(dev=%p):\n", __func__, dev); 17687a4c4eddSChristophe Roullier 17697a4c4eddSChristophe Roullier clk_free(&eqos->clk_tx); 17707a4c4eddSChristophe Roullier clk_free(&eqos->clk_rx); 17717a4c4eddSChristophe Roullier clk_free(&eqos->clk_master_bus); 17727a4c4eddSChristophe Roullier if (clk_valid(&eqos->clk_ck)) 17737a4c4eddSChristophe Roullier clk_free(&eqos->clk_ck); 17747a4c4eddSChristophe Roullier 17755bd3c538SChristophe Roullier if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) 17765bd3c538SChristophe Roullier dm_gpio_free(dev, &eqos->phy_reset_gpio); 17775bd3c538SChristophe Roullier 17787a4c4eddSChristophe Roullier debug("%s: OK\n", __func__); 17797a4c4eddSChristophe Roullier return 0; 17807a4c4eddSChristophe Roullier } 17817a4c4eddSChristophe Roullier 1782ba4dfef1SStephen Warren static int eqos_probe(struct udevice *dev) 1783ba4dfef1SStephen Warren { 1784ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1785ba4dfef1SStephen Warren int ret; 1786ba4dfef1SStephen Warren 1787ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1788ba4dfef1SStephen Warren 1789ba4dfef1SStephen Warren eqos->dev = dev; 1790ba4dfef1SStephen Warren eqos->config = (void *)dev_get_driver_data(dev); 1791ba4dfef1SStephen Warren 1792a821c4afSSimon Glass eqos->regs = devfdt_get_addr(dev); 1793ba4dfef1SStephen Warren if (eqos->regs == FDT_ADDR_T_NONE) { 179490aa625cSMasahiro Yamada pr_err("devfdt_get_addr() failed"); 1795ba4dfef1SStephen Warren return -ENODEV; 1796ba4dfef1SStephen Warren } 1797ba4dfef1SStephen Warren eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE); 1798ba4dfef1SStephen Warren eqos->mtl_regs = (void *)(eqos->regs + EQOS_MTL_REGS_BASE); 1799ba4dfef1SStephen Warren eqos->dma_regs = (void *)(eqos->regs + EQOS_DMA_REGS_BASE); 1800ba4dfef1SStephen Warren eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE); 1801ba4dfef1SStephen Warren 1802ba4dfef1SStephen Warren ret = eqos_probe_resources_core(dev); 1803ba4dfef1SStephen Warren if (ret < 0) { 180490aa625cSMasahiro Yamada pr_err("eqos_probe_resources_core() failed: %d", ret); 1805ba4dfef1SStephen Warren return ret; 1806ba4dfef1SStephen Warren } 1807ba4dfef1SStephen Warren 18087a4c4eddSChristophe Roullier ret = eqos->config->ops->eqos_probe_resources(dev); 1809ba4dfef1SStephen Warren if (ret < 0) { 18107a4c4eddSChristophe Roullier pr_err("eqos_probe_resources() failed: %d", ret); 1811ba4dfef1SStephen Warren goto err_remove_resources_core; 1812ba4dfef1SStephen Warren } 1813ba4dfef1SStephen Warren 1814ba4dfef1SStephen Warren eqos->mii = mdio_alloc(); 1815ba4dfef1SStephen Warren if (!eqos->mii) { 181690aa625cSMasahiro Yamada pr_err("mdio_alloc() failed"); 18177a4c4eddSChristophe Roullier ret = -ENOMEM; 1818ba4dfef1SStephen Warren goto err_remove_resources_tegra; 1819ba4dfef1SStephen Warren } 1820ba4dfef1SStephen Warren eqos->mii->read = eqos_mdio_read; 1821ba4dfef1SStephen Warren eqos->mii->write = eqos_mdio_write; 1822ba4dfef1SStephen Warren eqos->mii->priv = eqos; 1823ba4dfef1SStephen Warren strcpy(eqos->mii->name, dev->name); 1824ba4dfef1SStephen Warren 1825ba4dfef1SStephen Warren ret = mdio_register(eqos->mii); 1826ba4dfef1SStephen Warren if (ret < 0) { 182790aa625cSMasahiro Yamada pr_err("mdio_register() failed: %d", ret); 1828ba4dfef1SStephen Warren goto err_free_mdio; 1829ba4dfef1SStephen Warren } 1830ba4dfef1SStephen Warren 1831ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1832ba4dfef1SStephen Warren return 0; 1833ba4dfef1SStephen Warren 1834ba4dfef1SStephen Warren err_free_mdio: 1835ba4dfef1SStephen Warren mdio_free(eqos->mii); 1836ba4dfef1SStephen Warren err_remove_resources_tegra: 18377a4c4eddSChristophe Roullier eqos->config->ops->eqos_remove_resources(dev); 1838ba4dfef1SStephen Warren err_remove_resources_core: 1839ba4dfef1SStephen Warren eqos_remove_resources_core(dev); 1840ba4dfef1SStephen Warren 1841ba4dfef1SStephen Warren debug("%s: returns %d\n", __func__, ret); 1842ba4dfef1SStephen Warren return ret; 1843ba4dfef1SStephen Warren } 1844ba4dfef1SStephen Warren 1845ba4dfef1SStephen Warren static int eqos_remove(struct udevice *dev) 1846ba4dfef1SStephen Warren { 1847ba4dfef1SStephen Warren struct eqos_priv *eqos = dev_get_priv(dev); 1848ba4dfef1SStephen Warren 1849ba4dfef1SStephen Warren debug("%s(dev=%p):\n", __func__, dev); 1850ba4dfef1SStephen Warren 1851ba4dfef1SStephen Warren mdio_unregister(eqos->mii); 1852ba4dfef1SStephen Warren mdio_free(eqos->mii); 18537a4c4eddSChristophe Roullier eqos->config->ops->eqos_remove_resources(dev); 18547a4c4eddSChristophe Roullier 1855ba4dfef1SStephen Warren eqos_probe_resources_core(dev); 1856ba4dfef1SStephen Warren 1857ba4dfef1SStephen Warren debug("%s: OK\n", __func__); 1858ba4dfef1SStephen Warren return 0; 1859ba4dfef1SStephen Warren } 1860ba4dfef1SStephen Warren 1861ba4dfef1SStephen Warren static const struct eth_ops eqos_ops = { 1862ba4dfef1SStephen Warren .start = eqos_start, 1863ba4dfef1SStephen Warren .stop = eqos_stop, 1864ba4dfef1SStephen Warren .send = eqos_send, 1865ba4dfef1SStephen Warren .recv = eqos_recv, 1866ba4dfef1SStephen Warren .free_pkt = eqos_free_pkt, 1867ba4dfef1SStephen Warren .write_hwaddr = eqos_write_hwaddr, 1868ba4dfef1SStephen Warren }; 1869ba4dfef1SStephen Warren 18707a4c4eddSChristophe Roullier static struct eqos_ops eqos_tegra186_ops = { 18717a4c4eddSChristophe Roullier .eqos_inval_desc = eqos_inval_desc_tegra186, 18727a4c4eddSChristophe Roullier .eqos_flush_desc = eqos_flush_desc_tegra186, 18737a4c4eddSChristophe Roullier .eqos_inval_buffer = eqos_inval_buffer_tegra186, 18747a4c4eddSChristophe Roullier .eqos_flush_buffer = eqos_flush_buffer_tegra186, 18757a4c4eddSChristophe Roullier .eqos_probe_resources = eqos_probe_resources_tegra186, 18767a4c4eddSChristophe Roullier .eqos_remove_resources = eqos_remove_resources_tegra186, 18777a4c4eddSChristophe Roullier .eqos_stop_resets = eqos_stop_resets_tegra186, 18787a4c4eddSChristophe Roullier .eqos_start_resets = eqos_start_resets_tegra186, 18797a4c4eddSChristophe Roullier .eqos_stop_clks = eqos_stop_clks_tegra186, 18807a4c4eddSChristophe Roullier .eqos_start_clks = eqos_start_clks_tegra186, 18817a4c4eddSChristophe Roullier .eqos_calibrate_pads = eqos_calibrate_pads_tegra186, 18827a4c4eddSChristophe Roullier .eqos_disable_calibration = eqos_disable_calibration_tegra186, 18837a4c4eddSChristophe Roullier .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186, 18847a4c4eddSChristophe Roullier .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186 18857a4c4eddSChristophe Roullier }; 18867a4c4eddSChristophe Roullier 1887ba4dfef1SStephen Warren static const struct eqos_config eqos_tegra186_config = { 1888ba4dfef1SStephen Warren .reg_access_always_ok = false, 18897a4c4eddSChristophe Roullier .mdio_wait = 10, 18907a4c4eddSChristophe Roullier .swr_wait = 10, 18917a4c4eddSChristophe Roullier .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, 18927a4c4eddSChristophe Roullier .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, 18937a4c4eddSChristophe Roullier .interface = eqos_get_interface_tegra186, 18947a4c4eddSChristophe Roullier .ops = &eqos_tegra186_ops 18957a4c4eddSChristophe Roullier }; 18967a4c4eddSChristophe Roullier 18977a4c4eddSChristophe Roullier static struct eqos_ops eqos_stm32_ops = { 18987a4c4eddSChristophe Roullier .eqos_inval_desc = eqos_inval_desc_stm32, 18997a4c4eddSChristophe Roullier .eqos_flush_desc = eqos_flush_desc_stm32, 19007a4c4eddSChristophe Roullier .eqos_inval_buffer = eqos_inval_buffer_stm32, 19017a4c4eddSChristophe Roullier .eqos_flush_buffer = eqos_flush_buffer_stm32, 19027a4c4eddSChristophe Roullier .eqos_probe_resources = eqos_probe_resources_stm32, 19037a4c4eddSChristophe Roullier .eqos_remove_resources = eqos_remove_resources_stm32, 19047a4c4eddSChristophe Roullier .eqos_stop_resets = eqos_stop_resets_stm32, 19057a4c4eddSChristophe Roullier .eqos_start_resets = eqos_start_resets_stm32, 19067a4c4eddSChristophe Roullier .eqos_stop_clks = eqos_stop_clks_stm32, 19077a4c4eddSChristophe Roullier .eqos_start_clks = eqos_start_clks_stm32, 19087a4c4eddSChristophe Roullier .eqos_calibrate_pads = eqos_calibrate_pads_stm32, 19097a4c4eddSChristophe Roullier .eqos_disable_calibration = eqos_disable_calibration_stm32, 19107a4c4eddSChristophe Roullier .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32, 19117a4c4eddSChristophe Roullier .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32 19127a4c4eddSChristophe Roullier }; 19137a4c4eddSChristophe Roullier 19147a4c4eddSChristophe Roullier static const struct eqos_config eqos_stm32_config = { 19157a4c4eddSChristophe Roullier .reg_access_always_ok = false, 19167a4c4eddSChristophe Roullier .mdio_wait = 10000, 19177a4c4eddSChristophe Roullier .swr_wait = 50, 19187a4c4eddSChristophe Roullier .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, 19197a4c4eddSChristophe Roullier .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, 19207a4c4eddSChristophe Roullier .interface = eqos_get_interface_stm32, 19217a4c4eddSChristophe Roullier .ops = &eqos_stm32_ops 1922ba4dfef1SStephen Warren }; 1923ba4dfef1SStephen Warren 1924ba4dfef1SStephen Warren static const struct udevice_id eqos_ids[] = { 1925ba4dfef1SStephen Warren { 1926ba4dfef1SStephen Warren .compatible = "nvidia,tegra186-eqos", 1927ba4dfef1SStephen Warren .data = (ulong)&eqos_tegra186_config 1928ba4dfef1SStephen Warren }, 19297a4c4eddSChristophe Roullier { 19307a4c4eddSChristophe Roullier .compatible = "snps,dwmac-4.20a", 19317a4c4eddSChristophe Roullier .data = (ulong)&eqos_stm32_config 19327a4c4eddSChristophe Roullier }, 19337a4c4eddSChristophe Roullier 1934ba4dfef1SStephen Warren { } 1935ba4dfef1SStephen Warren }; 1936ba4dfef1SStephen Warren 1937ba4dfef1SStephen Warren U_BOOT_DRIVER(eth_eqos) = { 1938ba4dfef1SStephen Warren .name = "eth_eqos", 1939ba4dfef1SStephen Warren .id = UCLASS_ETH, 1940ba4dfef1SStephen Warren .of_match = eqos_ids, 1941ba4dfef1SStephen Warren .probe = eqos_probe, 1942ba4dfef1SStephen Warren .remove = eqos_remove, 1943ba4dfef1SStephen Warren .ops = &eqos_ops, 1944ba4dfef1SStephen Warren .priv_auto_alloc_size = sizeof(struct eqos_priv), 1945ba4dfef1SStephen Warren .platdata_auto_alloc_size = sizeof(struct eth_pdata), 1946ba4dfef1SStephen Warren }; 1947