1572890efSRavi Kumar /* SPDX-License-Identifier: BSD-3-Clause 2572890efSRavi Kumar * Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved. 3572890efSRavi Kumar * Copyright(c) 2018 Synopsys, Inc. All rights reserved. 4572890efSRavi Kumar */ 5572890efSRavi Kumar 6572890efSRavi Kumar #include "axgbe_ethdev.h" 7572890efSRavi Kumar #include "axgbe_common.h" 8572890efSRavi Kumar #include "axgbe_phy.h" 9572890efSRavi Kumar 10*4ac7516bSRavi Kumar /* query busy bit */ 11*4ac7516bSRavi Kumar static int mdio_complete(struct axgbe_port *pdata) 12*4ac7516bSRavi Kumar { 13*4ac7516bSRavi Kumar if (!AXGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, BUSY)) 14*4ac7516bSRavi Kumar return 1; 15*4ac7516bSRavi Kumar 16*4ac7516bSRavi Kumar return 0; 17*4ac7516bSRavi Kumar } 18*4ac7516bSRavi Kumar 19*4ac7516bSRavi Kumar static int axgbe_write_ext_mii_regs(struct axgbe_port *pdata, int addr, 20*4ac7516bSRavi Kumar int reg, u16 val) 21*4ac7516bSRavi Kumar { 22*4ac7516bSRavi Kumar unsigned int mdio_sca, mdio_sccd; 23*4ac7516bSRavi Kumar uint64_t timeout; 24*4ac7516bSRavi Kumar 25*4ac7516bSRavi Kumar mdio_sca = 0; 26*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg); 27*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr); 28*4ac7516bSRavi Kumar AXGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca); 29*4ac7516bSRavi Kumar 30*4ac7516bSRavi Kumar mdio_sccd = 0; 31*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, DATA, val); 32*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 1); 33*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1); 34*4ac7516bSRavi Kumar AXGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd); 35*4ac7516bSRavi Kumar 36*4ac7516bSRavi Kumar timeout = rte_get_timer_cycles() + rte_get_timer_hz(); 37*4ac7516bSRavi Kumar while (time_before(rte_get_timer_cycles(), timeout)) { 38*4ac7516bSRavi Kumar rte_delay_us(100); 39*4ac7516bSRavi Kumar if (mdio_complete(pdata)) 40*4ac7516bSRavi Kumar return 0; 41*4ac7516bSRavi Kumar } 42*4ac7516bSRavi Kumar 43*4ac7516bSRavi Kumar PMD_DRV_LOG(ERR, "Mdio write operation timed out\n"); 44*4ac7516bSRavi Kumar return -ETIMEDOUT; 45*4ac7516bSRavi Kumar } 46*4ac7516bSRavi Kumar 47*4ac7516bSRavi Kumar static int axgbe_read_ext_mii_regs(struct axgbe_port *pdata, int addr, 48*4ac7516bSRavi Kumar int reg) 49*4ac7516bSRavi Kumar { 50*4ac7516bSRavi Kumar unsigned int mdio_sca, mdio_sccd; 51*4ac7516bSRavi Kumar uint64_t timeout; 52*4ac7516bSRavi Kumar 53*4ac7516bSRavi Kumar mdio_sca = 0; 54*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg); 55*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr); 56*4ac7516bSRavi Kumar AXGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca); 57*4ac7516bSRavi Kumar 58*4ac7516bSRavi Kumar mdio_sccd = 0; 59*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 3); 60*4ac7516bSRavi Kumar AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1); 61*4ac7516bSRavi Kumar AXGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd); 62*4ac7516bSRavi Kumar 63*4ac7516bSRavi Kumar timeout = rte_get_timer_cycles() + rte_get_timer_hz(); 64*4ac7516bSRavi Kumar 65*4ac7516bSRavi Kumar while (time_before(rte_get_timer_cycles(), timeout)) { 66*4ac7516bSRavi Kumar rte_delay_us(100); 67*4ac7516bSRavi Kumar if (mdio_complete(pdata)) 68*4ac7516bSRavi Kumar goto success; 69*4ac7516bSRavi Kumar } 70*4ac7516bSRavi Kumar 71*4ac7516bSRavi Kumar PMD_DRV_LOG(ERR, "Mdio read operation timed out\n"); 72*4ac7516bSRavi Kumar return -ETIMEDOUT; 73*4ac7516bSRavi Kumar 74*4ac7516bSRavi Kumar success: 75*4ac7516bSRavi Kumar return AXGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, DATA); 76*4ac7516bSRavi Kumar } 77*4ac7516bSRavi Kumar 78*4ac7516bSRavi Kumar static int axgbe_set_ext_mii_mode(struct axgbe_port *pdata, unsigned int port, 79*4ac7516bSRavi Kumar enum axgbe_mdio_mode mode) 80*4ac7516bSRavi Kumar { 81*4ac7516bSRavi Kumar unsigned int reg_val = 0; 82*4ac7516bSRavi Kumar 83*4ac7516bSRavi Kumar switch (mode) { 84*4ac7516bSRavi Kumar case AXGBE_MDIO_MODE_CL22: 85*4ac7516bSRavi Kumar if (port > AXGMAC_MAX_C22_PORT) 86*4ac7516bSRavi Kumar return -EINVAL; 87*4ac7516bSRavi Kumar reg_val |= (1 << port); 88*4ac7516bSRavi Kumar break; 89*4ac7516bSRavi Kumar case AXGBE_MDIO_MODE_CL45: 90*4ac7516bSRavi Kumar break; 91*4ac7516bSRavi Kumar default: 92*4ac7516bSRavi Kumar return -EINVAL; 93*4ac7516bSRavi Kumar } 94*4ac7516bSRavi Kumar AXGMAC_IOWRITE(pdata, MAC_MDIOCL22R, reg_val); 95*4ac7516bSRavi Kumar 96*4ac7516bSRavi Kumar return 0; 97*4ac7516bSRavi Kumar } 98*4ac7516bSRavi Kumar 99*4ac7516bSRavi Kumar static int axgbe_read_mmd_regs_v2(struct axgbe_port *pdata, 100*4ac7516bSRavi Kumar int prtad __rte_unused, int mmd_reg) 101*4ac7516bSRavi Kumar { 102*4ac7516bSRavi Kumar unsigned int mmd_address, index, offset; 103*4ac7516bSRavi Kumar int mmd_data; 104*4ac7516bSRavi Kumar 105*4ac7516bSRavi Kumar if (mmd_reg & MII_ADDR_C45) 106*4ac7516bSRavi Kumar mmd_address = mmd_reg & ~MII_ADDR_C45; 107*4ac7516bSRavi Kumar else 108*4ac7516bSRavi Kumar mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); 109*4ac7516bSRavi Kumar 110*4ac7516bSRavi Kumar /* The PCS registers are accessed using mmio. The underlying 111*4ac7516bSRavi Kumar * management interface uses indirect addressing to access the MMD 112*4ac7516bSRavi Kumar * register sets. This requires accessing of the PCS register in two 113*4ac7516bSRavi Kumar * phases, an address phase and a data phase. 114*4ac7516bSRavi Kumar * 115*4ac7516bSRavi Kumar * The mmio interface is based on 16-bit offsets and values. All 116*4ac7516bSRavi Kumar * register offsets must therefore be adjusted by left shifting the 117*4ac7516bSRavi Kumar * offset 1 bit and reading 16 bits of data. 118*4ac7516bSRavi Kumar */ 119*4ac7516bSRavi Kumar mmd_address <<= 1; 120*4ac7516bSRavi Kumar index = mmd_address & ~pdata->xpcs_window_mask; 121*4ac7516bSRavi Kumar offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask); 122*4ac7516bSRavi Kumar 123*4ac7516bSRavi Kumar pthread_mutex_lock(&pdata->xpcs_mutex); 124*4ac7516bSRavi Kumar 125*4ac7516bSRavi Kumar XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index); 126*4ac7516bSRavi Kumar mmd_data = XPCS16_IOREAD(pdata, offset); 127*4ac7516bSRavi Kumar 128*4ac7516bSRavi Kumar pthread_mutex_unlock(&pdata->xpcs_mutex); 129*4ac7516bSRavi Kumar 130*4ac7516bSRavi Kumar return mmd_data; 131*4ac7516bSRavi Kumar } 132*4ac7516bSRavi Kumar 133*4ac7516bSRavi Kumar static void axgbe_write_mmd_regs_v2(struct axgbe_port *pdata, 134*4ac7516bSRavi Kumar int prtad __rte_unused, 135*4ac7516bSRavi Kumar int mmd_reg, int mmd_data) 136*4ac7516bSRavi Kumar { 137*4ac7516bSRavi Kumar unsigned int mmd_address, index, offset; 138*4ac7516bSRavi Kumar 139*4ac7516bSRavi Kumar if (mmd_reg & MII_ADDR_C45) 140*4ac7516bSRavi Kumar mmd_address = mmd_reg & ~MII_ADDR_C45; 141*4ac7516bSRavi Kumar else 142*4ac7516bSRavi Kumar mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); 143*4ac7516bSRavi Kumar 144*4ac7516bSRavi Kumar /* The PCS registers are accessed using mmio. The underlying 145*4ac7516bSRavi Kumar * management interface uses indirect addressing to access the MMD 146*4ac7516bSRavi Kumar * register sets. This requires accessing of the PCS register in two 147*4ac7516bSRavi Kumar * phases, an address phase and a data phase. 148*4ac7516bSRavi Kumar * 149*4ac7516bSRavi Kumar * The mmio interface is based on 16-bit offsets and values. All 150*4ac7516bSRavi Kumar * register offsets must therefore be adjusted by left shifting the 151*4ac7516bSRavi Kumar * offset 1 bit and writing 16 bits of data. 152*4ac7516bSRavi Kumar */ 153*4ac7516bSRavi Kumar mmd_address <<= 1; 154*4ac7516bSRavi Kumar index = mmd_address & ~pdata->xpcs_window_mask; 155*4ac7516bSRavi Kumar offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask); 156*4ac7516bSRavi Kumar 157*4ac7516bSRavi Kumar pthread_mutex_lock(&pdata->xpcs_mutex); 158*4ac7516bSRavi Kumar 159*4ac7516bSRavi Kumar XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index); 160*4ac7516bSRavi Kumar XPCS16_IOWRITE(pdata, offset, mmd_data); 161*4ac7516bSRavi Kumar 162*4ac7516bSRavi Kumar pthread_mutex_unlock(&pdata->xpcs_mutex); 163*4ac7516bSRavi Kumar } 164*4ac7516bSRavi Kumar 165*4ac7516bSRavi Kumar static int axgbe_read_mmd_regs(struct axgbe_port *pdata, int prtad, 166*4ac7516bSRavi Kumar int mmd_reg) 167*4ac7516bSRavi Kumar { 168*4ac7516bSRavi Kumar switch (pdata->vdata->xpcs_access) { 169*4ac7516bSRavi Kumar case AXGBE_XPCS_ACCESS_V1: 170*4ac7516bSRavi Kumar PMD_DRV_LOG(ERR, "PHY_Version 1 is not supported\n"); 171*4ac7516bSRavi Kumar return -1; 172*4ac7516bSRavi Kumar case AXGBE_XPCS_ACCESS_V2: 173*4ac7516bSRavi Kumar default: 174*4ac7516bSRavi Kumar return axgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg); 175*4ac7516bSRavi Kumar } 176*4ac7516bSRavi Kumar } 177*4ac7516bSRavi Kumar 178*4ac7516bSRavi Kumar static void axgbe_write_mmd_regs(struct axgbe_port *pdata, int prtad, 179*4ac7516bSRavi Kumar int mmd_reg, int mmd_data) 180*4ac7516bSRavi Kumar { 181*4ac7516bSRavi Kumar switch (pdata->vdata->xpcs_access) { 182*4ac7516bSRavi Kumar case AXGBE_XPCS_ACCESS_V1: 183*4ac7516bSRavi Kumar PMD_DRV_LOG(ERR, "PHY_Version 1 is not supported\n"); 184*4ac7516bSRavi Kumar return; 185*4ac7516bSRavi Kumar case AXGBE_XPCS_ACCESS_V2: 186*4ac7516bSRavi Kumar default: 187*4ac7516bSRavi Kumar return axgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data); 188*4ac7516bSRavi Kumar } 189*4ac7516bSRavi Kumar } 190*4ac7516bSRavi Kumar 191572890efSRavi Kumar static int __axgbe_exit(struct axgbe_port *pdata) 192572890efSRavi Kumar { 193572890efSRavi Kumar unsigned int count = 2000; 194572890efSRavi Kumar 195572890efSRavi Kumar /* Issue a software reset */ 196572890efSRavi Kumar AXGMAC_IOWRITE_BITS(pdata, DMA_MR, SWR, 1); 197572890efSRavi Kumar rte_delay_us(10); 198572890efSRavi Kumar 199572890efSRavi Kumar /* Poll Until Poll Condition */ 200572890efSRavi Kumar while (--count && AXGMAC_IOREAD_BITS(pdata, DMA_MR, SWR)) 201572890efSRavi Kumar rte_delay_us(500); 202572890efSRavi Kumar 203572890efSRavi Kumar if (!count) 204572890efSRavi Kumar return -EBUSY; 205572890efSRavi Kumar 206572890efSRavi Kumar return 0; 207572890efSRavi Kumar } 208572890efSRavi Kumar 209572890efSRavi Kumar static int axgbe_exit(struct axgbe_port *pdata) 210572890efSRavi Kumar { 211572890efSRavi Kumar int ret; 212572890efSRavi Kumar 213572890efSRavi Kumar /* To guard against possible incorrectly generated interrupts, 214572890efSRavi Kumar * issue the software reset twice. 215572890efSRavi Kumar */ 216572890efSRavi Kumar ret = __axgbe_exit(pdata); 217572890efSRavi Kumar if (ret) 218572890efSRavi Kumar return ret; 219572890efSRavi Kumar 220572890efSRavi Kumar return __axgbe_exit(pdata); 221572890efSRavi Kumar } 222572890efSRavi Kumar 223572890efSRavi Kumar void axgbe_init_function_ptrs_dev(struct axgbe_hw_if *hw_if) 224572890efSRavi Kumar { 225572890efSRavi Kumar hw_if->exit = axgbe_exit; 226*4ac7516bSRavi Kumar 227*4ac7516bSRavi Kumar hw_if->read_mmd_regs = axgbe_read_mmd_regs; 228*4ac7516bSRavi Kumar hw_if->write_mmd_regs = axgbe_write_mmd_regs; 229*4ac7516bSRavi Kumar 230*4ac7516bSRavi Kumar hw_if->set_ext_mii_mode = axgbe_set_ext_mii_mode; 231*4ac7516bSRavi Kumar hw_if->read_ext_mii_regs = axgbe_read_ext_mii_regs; 232*4ac7516bSRavi Kumar hw_if->write_ext_mii_regs = axgbe_write_ext_mii_regs; 233572890efSRavi Kumar } 234