1e57f7a3fSLendacky, Thomas /* 2e57f7a3fSLendacky, Thomas * AMD 10Gb Ethernet driver 3e57f7a3fSLendacky, Thomas * 4e57f7a3fSLendacky, Thomas * This file is available to you under your choice of the following two 5e57f7a3fSLendacky, Thomas * licenses: 6e57f7a3fSLendacky, Thomas * 7e57f7a3fSLendacky, Thomas * License 1: GPLv2 8e57f7a3fSLendacky, Thomas * 9e57f7a3fSLendacky, Thomas * Copyright (c) 2016 Advanced Micro Devices, Inc. 10e57f7a3fSLendacky, Thomas * 11e57f7a3fSLendacky, Thomas * This file is free software; you may copy, redistribute and/or modify 12e57f7a3fSLendacky, Thomas * it under the terms of the GNU General Public License as published by 13e57f7a3fSLendacky, Thomas * the Free Software Foundation, either version 2 of the License, or (at 14e57f7a3fSLendacky, Thomas * your option) any later version. 15e57f7a3fSLendacky, Thomas * 16e57f7a3fSLendacky, Thomas * This file is distributed in the hope that it will be useful, but 17e57f7a3fSLendacky, Thomas * WITHOUT ANY WARRANTY; without even the implied warranty of 18e57f7a3fSLendacky, Thomas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19e57f7a3fSLendacky, Thomas * General Public License for more details. 20e57f7a3fSLendacky, Thomas * 21e57f7a3fSLendacky, Thomas * You should have received a copy of the GNU General Public License 22e57f7a3fSLendacky, Thomas * along with this program. If not, see <http://www.gnu.org/licenses/>. 23e57f7a3fSLendacky, Thomas * 24e57f7a3fSLendacky, Thomas * This file incorporates work covered by the following copyright and 25e57f7a3fSLendacky, Thomas * permission notice: 26e57f7a3fSLendacky, Thomas * The Synopsys DWC ETHER XGMAC Software Driver and documentation 27e57f7a3fSLendacky, Thomas * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 28e57f7a3fSLendacky, Thomas * Inc. unless otherwise expressly agreed to in writing between Synopsys 29e57f7a3fSLendacky, Thomas * and you. 30e57f7a3fSLendacky, Thomas * 31e57f7a3fSLendacky, Thomas * The Software IS NOT an item of Licensed Software or Licensed Product 32e57f7a3fSLendacky, Thomas * under any End User Software License Agreement or Agreement for Licensed 33e57f7a3fSLendacky, Thomas * Product with Synopsys or any supplement thereto. Permission is hereby 34e57f7a3fSLendacky, Thomas * granted, free of charge, to any person obtaining a copy of this software 35e57f7a3fSLendacky, Thomas * annotated with this license and the Software, to deal in the Software 36e57f7a3fSLendacky, Thomas * without restriction, including without limitation the rights to use, 37e57f7a3fSLendacky, Thomas * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 38e57f7a3fSLendacky, Thomas * of the Software, and to permit persons to whom the Software is furnished 39e57f7a3fSLendacky, Thomas * to do so, subject to the following conditions: 40e57f7a3fSLendacky, Thomas * 41e57f7a3fSLendacky, Thomas * The above copyright notice and this permission notice shall be included 42e57f7a3fSLendacky, Thomas * in all copies or substantial portions of the Software. 43e57f7a3fSLendacky, Thomas * 44e57f7a3fSLendacky, Thomas * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 45e57f7a3fSLendacky, Thomas * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46e57f7a3fSLendacky, Thomas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47e57f7a3fSLendacky, Thomas * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 48e57f7a3fSLendacky, Thomas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 49e57f7a3fSLendacky, Thomas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 50e57f7a3fSLendacky, Thomas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 51e57f7a3fSLendacky, Thomas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 52e57f7a3fSLendacky, Thomas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53e57f7a3fSLendacky, Thomas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 54e57f7a3fSLendacky, Thomas * THE POSSIBILITY OF SUCH DAMAGE. 55e57f7a3fSLendacky, Thomas * 56e57f7a3fSLendacky, Thomas * 57e57f7a3fSLendacky, Thomas * License 2: Modified BSD 58e57f7a3fSLendacky, Thomas * 59e57f7a3fSLendacky, Thomas * Copyright (c) 2016 Advanced Micro Devices, Inc. 60e57f7a3fSLendacky, Thomas * All rights reserved. 61e57f7a3fSLendacky, Thomas * 62e57f7a3fSLendacky, Thomas * Redistribution and use in source and binary forms, with or without 63e57f7a3fSLendacky, Thomas * modification, are permitted provided that the following conditions are met: 64e57f7a3fSLendacky, Thomas * * Redistributions of source code must retain the above copyright 65e57f7a3fSLendacky, Thomas * notice, this list of conditions and the following disclaimer. 66e57f7a3fSLendacky, Thomas * * Redistributions in binary form must reproduce the above copyright 67e57f7a3fSLendacky, Thomas * notice, this list of conditions and the following disclaimer in the 68e57f7a3fSLendacky, Thomas * documentation and/or other materials provided with the distribution. 69e57f7a3fSLendacky, Thomas * * Neither the name of Advanced Micro Devices, Inc. nor the 70e57f7a3fSLendacky, Thomas * names of its contributors may be used to endorse or promote products 71e57f7a3fSLendacky, Thomas * derived from this software without specific prior written permission. 72e57f7a3fSLendacky, Thomas * 73e57f7a3fSLendacky, Thomas * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 74e57f7a3fSLendacky, Thomas * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 75e57f7a3fSLendacky, Thomas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 76e57f7a3fSLendacky, Thomas * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 77e57f7a3fSLendacky, Thomas * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 78e57f7a3fSLendacky, Thomas * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 79e57f7a3fSLendacky, Thomas * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 80e57f7a3fSLendacky, Thomas * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 81e57f7a3fSLendacky, Thomas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 82e57f7a3fSLendacky, Thomas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 83e57f7a3fSLendacky, Thomas * 84e57f7a3fSLendacky, Thomas * This file incorporates work covered by the following copyright and 85e57f7a3fSLendacky, Thomas * permission notice: 86e57f7a3fSLendacky, Thomas * The Synopsys DWC ETHER XGMAC Software Driver and documentation 87e57f7a3fSLendacky, Thomas * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 88e57f7a3fSLendacky, Thomas * Inc. unless otherwise expressly agreed to in writing between Synopsys 89e57f7a3fSLendacky, Thomas * and you. 90e57f7a3fSLendacky, Thomas * 91e57f7a3fSLendacky, Thomas * The Software IS NOT an item of Licensed Software or Licensed Product 92e57f7a3fSLendacky, Thomas * under any End User Software License Agreement or Agreement for Licensed 93e57f7a3fSLendacky, Thomas * Product with Synopsys or any supplement thereto. Permission is hereby 94e57f7a3fSLendacky, Thomas * granted, free of charge, to any person obtaining a copy of this software 95e57f7a3fSLendacky, Thomas * annotated with this license and the Software, to deal in the Software 96e57f7a3fSLendacky, Thomas * without restriction, including without limitation the rights to use, 97e57f7a3fSLendacky, Thomas * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 98e57f7a3fSLendacky, Thomas * of the Software, and to permit persons to whom the Software is furnished 99e57f7a3fSLendacky, Thomas * to do so, subject to the following conditions: 100e57f7a3fSLendacky, Thomas * 101e57f7a3fSLendacky, Thomas * The above copyright notice and this permission notice shall be included 102e57f7a3fSLendacky, Thomas * in all copies or substantial portions of the Software. 103e57f7a3fSLendacky, Thomas * 104e57f7a3fSLendacky, Thomas * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 105e57f7a3fSLendacky, Thomas * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 106e57f7a3fSLendacky, Thomas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 107e57f7a3fSLendacky, Thomas * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 108e57f7a3fSLendacky, Thomas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 109e57f7a3fSLendacky, Thomas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 110e57f7a3fSLendacky, Thomas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 111e57f7a3fSLendacky, Thomas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 112e57f7a3fSLendacky, Thomas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 113e57f7a3fSLendacky, Thomas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 114e57f7a3fSLendacky, Thomas * THE POSSIBILITY OF SUCH DAMAGE. 115e57f7a3fSLendacky, Thomas */ 116e57f7a3fSLendacky, Thomas 117e57f7a3fSLendacky, Thomas #include <linux/module.h> 118e57f7a3fSLendacky, Thomas #include <linux/kmod.h> 119e57f7a3fSLendacky, Thomas #include <linux/device.h> 120e57f7a3fSLendacky, Thomas #include <linux/property.h> 121e57f7a3fSLendacky, Thomas #include <linux/mdio.h> 122e57f7a3fSLendacky, Thomas #include <linux/phy.h> 123e57f7a3fSLendacky, Thomas 124e57f7a3fSLendacky, Thomas #include "xgbe.h" 125e57f7a3fSLendacky, Thomas #include "xgbe-common.h" 126e57f7a3fSLendacky, Thomas 127e57f7a3fSLendacky, Thomas #define XGBE_BLWC_PROPERTY "amd,serdes-blwc" 128e57f7a3fSLendacky, Thomas #define XGBE_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" 129e57f7a3fSLendacky, Thomas #define XGBE_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" 130e57f7a3fSLendacky, Thomas #define XGBE_TX_AMP_PROPERTY "amd,serdes-tx-amp" 131e57f7a3fSLendacky, Thomas #define XGBE_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config" 132e57f7a3fSLendacky, Thomas #define XGBE_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable" 133e57f7a3fSLendacky, Thomas 134e57f7a3fSLendacky, Thomas /* Default SerDes settings */ 135e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_BLWC 1 136e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_CDR 0x2 137e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_PLL 0x0 138e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_PQ 0xa 139e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_RATE 0x3 140e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_TXAMP 0xf 141e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_WORD 0x1 142e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_DFE_TAP_CONFIG 0x3 143e57f7a3fSLendacky, Thomas #define XGBE_SPEED_1000_DFE_TAP_ENABLE 0x0 144e57f7a3fSLendacky, Thomas 145e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_BLWC 1 146e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_CDR 0x2 147e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_PLL 0x0 148e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_PQ 0xa 149e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_RATE 0x1 150e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_TXAMP 0xf 151e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_WORD 0x1 152e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_DFE_TAP_CONFIG 0x3 153e57f7a3fSLendacky, Thomas #define XGBE_SPEED_2500_DFE_TAP_ENABLE 0x0 154e57f7a3fSLendacky, Thomas 155e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_BLWC 0 156e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_CDR 0x7 157e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_PLL 0x1 158e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_PQ 0x12 159e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_RATE 0x0 160e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_TXAMP 0xa 161e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_WORD 0x7 162e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_DFE_TAP_CONFIG 0x1 163e57f7a3fSLendacky, Thomas #define XGBE_SPEED_10000_DFE_TAP_ENABLE 0x7f 164e57f7a3fSLendacky, Thomas 165e57f7a3fSLendacky, Thomas /* Rate-change complete wait/retry count */ 166e57f7a3fSLendacky, Thomas #define XGBE_RATECHANGE_COUNT 500 167e57f7a3fSLendacky, Thomas 168e57f7a3fSLendacky, Thomas static const u32 xgbe_phy_blwc[] = { 169e57f7a3fSLendacky, Thomas XGBE_SPEED_1000_BLWC, 170e57f7a3fSLendacky, Thomas XGBE_SPEED_2500_BLWC, 171e57f7a3fSLendacky, Thomas XGBE_SPEED_10000_BLWC, 172e57f7a3fSLendacky, Thomas }; 173e57f7a3fSLendacky, Thomas 174e57f7a3fSLendacky, Thomas static const u32 xgbe_phy_cdr_rate[] = { 175e57f7a3fSLendacky, Thomas XGBE_SPEED_1000_CDR, 176e57f7a3fSLendacky, Thomas XGBE_SPEED_2500_CDR, 177e57f7a3fSLendacky, Thomas XGBE_SPEED_10000_CDR, 178e57f7a3fSLendacky, Thomas }; 179e57f7a3fSLendacky, Thomas 180e57f7a3fSLendacky, Thomas static const u32 xgbe_phy_pq_skew[] = { 181e57f7a3fSLendacky, Thomas XGBE_SPEED_1000_PQ, 182e57f7a3fSLendacky, Thomas XGBE_SPEED_2500_PQ, 183e57f7a3fSLendacky, Thomas XGBE_SPEED_10000_PQ, 184e57f7a3fSLendacky, Thomas }; 185e57f7a3fSLendacky, Thomas 186e57f7a3fSLendacky, Thomas static const u32 xgbe_phy_tx_amp[] = { 187e57f7a3fSLendacky, Thomas XGBE_SPEED_1000_TXAMP, 188e57f7a3fSLendacky, Thomas XGBE_SPEED_2500_TXAMP, 189e57f7a3fSLendacky, Thomas XGBE_SPEED_10000_TXAMP, 190e57f7a3fSLendacky, Thomas }; 191e57f7a3fSLendacky, Thomas 192e57f7a3fSLendacky, Thomas static const u32 xgbe_phy_dfe_tap_cfg[] = { 193e57f7a3fSLendacky, Thomas XGBE_SPEED_1000_DFE_TAP_CONFIG, 194e57f7a3fSLendacky, Thomas XGBE_SPEED_2500_DFE_TAP_CONFIG, 195e57f7a3fSLendacky, Thomas XGBE_SPEED_10000_DFE_TAP_CONFIG, 196e57f7a3fSLendacky, Thomas }; 197e57f7a3fSLendacky, Thomas 198e57f7a3fSLendacky, Thomas static const u32 xgbe_phy_dfe_tap_ena[] = { 199e57f7a3fSLendacky, Thomas XGBE_SPEED_1000_DFE_TAP_ENABLE, 200e57f7a3fSLendacky, Thomas XGBE_SPEED_2500_DFE_TAP_ENABLE, 201e57f7a3fSLendacky, Thomas XGBE_SPEED_10000_DFE_TAP_ENABLE, 202e57f7a3fSLendacky, Thomas }; 203e57f7a3fSLendacky, Thomas 204e57f7a3fSLendacky, Thomas struct xgbe_phy_data { 205e57f7a3fSLendacky, Thomas /* 1000/10000 vs 2500/10000 indicator */ 206e57f7a3fSLendacky, Thomas unsigned int speed_set; 207e57f7a3fSLendacky, Thomas 208e57f7a3fSLendacky, Thomas /* SerDes UEFI configurable settings. 209e57f7a3fSLendacky, Thomas * Switching between modes/speeds requires new values for some 210e57f7a3fSLendacky, Thomas * SerDes settings. The values can be supplied as device 211e57f7a3fSLendacky, Thomas * properties in array format. The first array entry is for 212e57f7a3fSLendacky, Thomas * 1GbE, second for 2.5GbE and third for 10GbE 213e57f7a3fSLendacky, Thomas */ 214e57f7a3fSLendacky, Thomas u32 blwc[XGBE_SPEEDS]; 215e57f7a3fSLendacky, Thomas u32 cdr_rate[XGBE_SPEEDS]; 216e57f7a3fSLendacky, Thomas u32 pq_skew[XGBE_SPEEDS]; 217e57f7a3fSLendacky, Thomas u32 tx_amp[XGBE_SPEEDS]; 218e57f7a3fSLendacky, Thomas u32 dfe_tap_cfg[XGBE_SPEEDS]; 219e57f7a3fSLendacky, Thomas u32 dfe_tap_ena[XGBE_SPEEDS]; 220e57f7a3fSLendacky, Thomas }; 221e57f7a3fSLendacky, Thomas 222e57f7a3fSLendacky, Thomas static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) 223e57f7a3fSLendacky, Thomas { 224e57f7a3fSLendacky, Thomas XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1); 225e57f7a3fSLendacky, Thomas } 226e57f7a3fSLendacky, Thomas 227e57f7a3fSLendacky, Thomas static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) 228e57f7a3fSLendacky, Thomas { 229e57f7a3fSLendacky, Thomas XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0); 230e57f7a3fSLendacky, Thomas } 231e57f7a3fSLendacky, Thomas 232e57f7a3fSLendacky, Thomas static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) 233e57f7a3fSLendacky, Thomas { 234e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 235e57f7a3fSLendacky, Thomas enum xgbe_mode mode; 236e57f7a3fSLendacky, Thomas unsigned int ad_reg, lp_reg; 237e57f7a3fSLendacky, Thomas 238e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_Autoneg; 239e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_Backplane; 240e57f7a3fSLendacky, Thomas 241e57f7a3fSLendacky, Thomas /* Compare Advertisement and Link Partner register 1 */ 242e57f7a3fSLendacky, Thomas ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 243e57f7a3fSLendacky, Thomas lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); 244e57f7a3fSLendacky, Thomas if (lp_reg & 0x400) 245e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_Pause; 246e57f7a3fSLendacky, Thomas if (lp_reg & 0x800) 247e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; 248e57f7a3fSLendacky, Thomas 249e57f7a3fSLendacky, Thomas if (pdata->phy.pause_autoneg) { 250e57f7a3fSLendacky, Thomas /* Set flow control based on auto-negotiation result */ 251e57f7a3fSLendacky, Thomas pdata->phy.tx_pause = 0; 252e57f7a3fSLendacky, Thomas pdata->phy.rx_pause = 0; 253e57f7a3fSLendacky, Thomas 254e57f7a3fSLendacky, Thomas if (ad_reg & lp_reg & 0x400) { 255e57f7a3fSLendacky, Thomas pdata->phy.tx_pause = 1; 256e57f7a3fSLendacky, Thomas pdata->phy.rx_pause = 1; 257e57f7a3fSLendacky, Thomas } else if (ad_reg & lp_reg & 0x800) { 258e57f7a3fSLendacky, Thomas if (ad_reg & 0x400) 259e57f7a3fSLendacky, Thomas pdata->phy.rx_pause = 1; 260e57f7a3fSLendacky, Thomas else if (lp_reg & 0x400) 261e57f7a3fSLendacky, Thomas pdata->phy.tx_pause = 1; 262e57f7a3fSLendacky, Thomas } 263e57f7a3fSLendacky, Thomas } 264e57f7a3fSLendacky, Thomas 265e57f7a3fSLendacky, Thomas /* Compare Advertisement and Link Partner register 2 */ 266e57f7a3fSLendacky, Thomas ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 267e57f7a3fSLendacky, Thomas lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 268e57f7a3fSLendacky, Thomas if (lp_reg & 0x80) 269e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; 270e57f7a3fSLendacky, Thomas if (lp_reg & 0x20) { 271e57f7a3fSLendacky, Thomas if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 272e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full; 273e57f7a3fSLendacky, Thomas else 274e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; 275e57f7a3fSLendacky, Thomas } 276e57f7a3fSLendacky, Thomas 277e57f7a3fSLendacky, Thomas ad_reg &= lp_reg; 278e57f7a3fSLendacky, Thomas if (ad_reg & 0x80) { 279e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KR; 280e57f7a3fSLendacky, Thomas } else if (ad_reg & 0x20) { 281e57f7a3fSLendacky, Thomas if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 282e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KX_2500; 283e57f7a3fSLendacky, Thomas else 284e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KX_1000; 285e57f7a3fSLendacky, Thomas } else { 286e57f7a3fSLendacky, Thomas mode = XGBE_MODE_UNKNOWN; 287e57f7a3fSLendacky, Thomas } 288e57f7a3fSLendacky, Thomas 289e57f7a3fSLendacky, Thomas /* Compare Advertisement and Link Partner register 3 */ 290e57f7a3fSLendacky, Thomas ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 291e57f7a3fSLendacky, Thomas lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 292e57f7a3fSLendacky, Thomas if (lp_reg & 0xc000) 293e57f7a3fSLendacky, Thomas pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; 294e57f7a3fSLendacky, Thomas 295e57f7a3fSLendacky, Thomas return mode; 296e57f7a3fSLendacky, Thomas } 297e57f7a3fSLendacky, Thomas 298*a64def41SLendacky, Thomas static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) 299*a64def41SLendacky, Thomas { 300*a64def41SLendacky, Thomas return XGBE_AN_MODE_CL73; 301*a64def41SLendacky, Thomas } 302*a64def41SLendacky, Thomas 303e57f7a3fSLendacky, Thomas static void xgbe_phy_pcs_power_cycle(struct xgbe_prv_data *pdata) 304e57f7a3fSLendacky, Thomas { 305e57f7a3fSLendacky, Thomas unsigned int reg; 306e57f7a3fSLendacky, Thomas 307e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 308e57f7a3fSLendacky, Thomas 309e57f7a3fSLendacky, Thomas reg |= MDIO_CTRL1_LPOWER; 310e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 311e57f7a3fSLendacky, Thomas 312e57f7a3fSLendacky, Thomas usleep_range(75, 100); 313e57f7a3fSLendacky, Thomas 314e57f7a3fSLendacky, Thomas reg &= ~MDIO_CTRL1_LPOWER; 315e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 316e57f7a3fSLendacky, Thomas } 317e57f7a3fSLendacky, Thomas 318e57f7a3fSLendacky, Thomas static void xgbe_phy_start_ratechange(struct xgbe_prv_data *pdata) 319e57f7a3fSLendacky, Thomas { 320e57f7a3fSLendacky, Thomas /* Assert Rx and Tx ratechange */ 321e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1); 322e57f7a3fSLendacky, Thomas } 323e57f7a3fSLendacky, Thomas 324e57f7a3fSLendacky, Thomas static void xgbe_phy_complete_ratechange(struct xgbe_prv_data *pdata) 325e57f7a3fSLendacky, Thomas { 326e57f7a3fSLendacky, Thomas unsigned int wait; 327e57f7a3fSLendacky, Thomas u16 status; 328e57f7a3fSLendacky, Thomas 329e57f7a3fSLendacky, Thomas /* Release Rx and Tx ratechange */ 330e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0); 331e57f7a3fSLendacky, Thomas 332e57f7a3fSLendacky, Thomas /* Wait for Rx and Tx ready */ 333e57f7a3fSLendacky, Thomas wait = XGBE_RATECHANGE_COUNT; 334e57f7a3fSLendacky, Thomas while (wait--) { 335e57f7a3fSLendacky, Thomas usleep_range(50, 75); 336e57f7a3fSLendacky, Thomas 337e57f7a3fSLendacky, Thomas status = XSIR0_IOREAD(pdata, SIR0_STATUS); 338e57f7a3fSLendacky, Thomas if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && 339e57f7a3fSLendacky, Thomas XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) 340e57f7a3fSLendacky, Thomas goto rx_reset; 341e57f7a3fSLendacky, Thomas } 342e57f7a3fSLendacky, Thomas 343e57f7a3fSLendacky, Thomas netif_dbg(pdata, link, pdata->netdev, "SerDes rx/tx not ready (%#hx)\n", 344e57f7a3fSLendacky, Thomas status); 345e57f7a3fSLendacky, Thomas 346e57f7a3fSLendacky, Thomas rx_reset: 347e57f7a3fSLendacky, Thomas /* Perform Rx reset for the DFE changes */ 348e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 0); 349e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 1); 350e57f7a3fSLendacky, Thomas } 351e57f7a3fSLendacky, Thomas 352e57f7a3fSLendacky, Thomas static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) 353e57f7a3fSLendacky, Thomas { 354e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 355e57f7a3fSLendacky, Thomas unsigned int reg; 356e57f7a3fSLendacky, Thomas 357e57f7a3fSLendacky, Thomas /* Set PCS to KR/10G speed */ 358e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 359e57f7a3fSLendacky, Thomas reg &= ~MDIO_PCS_CTRL2_TYPE; 360e57f7a3fSLendacky, Thomas reg |= MDIO_PCS_CTRL2_10GBR; 361e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); 362e57f7a3fSLendacky, Thomas 363e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 364e57f7a3fSLendacky, Thomas reg &= ~MDIO_CTRL1_SPEEDSEL; 365e57f7a3fSLendacky, Thomas reg |= MDIO_CTRL1_SPEED10G; 366e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 367e57f7a3fSLendacky, Thomas 368e57f7a3fSLendacky, Thomas xgbe_phy_pcs_power_cycle(pdata); 369e57f7a3fSLendacky, Thomas 370e57f7a3fSLendacky, Thomas /* Set SerDes to 10G speed */ 371e57f7a3fSLendacky, Thomas xgbe_phy_start_ratechange(pdata); 372e57f7a3fSLendacky, Thomas 373e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_10000_RATE); 374e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_10000_WORD); 375e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_10000_PLL); 376e57f7a3fSLendacky, Thomas 377e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, 378e57f7a3fSLendacky, Thomas phy_data->cdr_rate[XGBE_SPEED_10000]); 379e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, 380e57f7a3fSLendacky, Thomas phy_data->tx_amp[XGBE_SPEED_10000]); 381e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, 382e57f7a3fSLendacky, Thomas phy_data->blwc[XGBE_SPEED_10000]); 383e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, 384e57f7a3fSLendacky, Thomas phy_data->pq_skew[XGBE_SPEED_10000]); 385e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, 386e57f7a3fSLendacky, Thomas phy_data->dfe_tap_cfg[XGBE_SPEED_10000]); 387e57f7a3fSLendacky, Thomas XRXTX_IOWRITE(pdata, RXTX_REG22, 388e57f7a3fSLendacky, Thomas phy_data->dfe_tap_ena[XGBE_SPEED_10000]); 389e57f7a3fSLendacky, Thomas 390e57f7a3fSLendacky, Thomas xgbe_phy_complete_ratechange(pdata); 391e57f7a3fSLendacky, Thomas 392e57f7a3fSLendacky, Thomas netif_dbg(pdata, link, pdata->netdev, "10GbE KR mode set\n"); 393e57f7a3fSLendacky, Thomas } 394e57f7a3fSLendacky, Thomas 395e57f7a3fSLendacky, Thomas static void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) 396e57f7a3fSLendacky, Thomas { 397e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 398e57f7a3fSLendacky, Thomas unsigned int reg; 399e57f7a3fSLendacky, Thomas 400e57f7a3fSLendacky, Thomas /* Set PCS to KX/1G speed */ 401e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 402e57f7a3fSLendacky, Thomas reg &= ~MDIO_PCS_CTRL2_TYPE; 403e57f7a3fSLendacky, Thomas reg |= MDIO_PCS_CTRL2_10GBX; 404e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); 405e57f7a3fSLendacky, Thomas 406e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 407e57f7a3fSLendacky, Thomas reg &= ~MDIO_CTRL1_SPEEDSEL; 408e57f7a3fSLendacky, Thomas reg |= MDIO_CTRL1_SPEED1G; 409e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 410e57f7a3fSLendacky, Thomas 411e57f7a3fSLendacky, Thomas xgbe_phy_pcs_power_cycle(pdata); 412e57f7a3fSLendacky, Thomas 413e57f7a3fSLendacky, Thomas /* Set SerDes to 2.5G speed */ 414e57f7a3fSLendacky, Thomas xgbe_phy_start_ratechange(pdata); 415e57f7a3fSLendacky, Thomas 416e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_2500_RATE); 417e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_2500_WORD); 418e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_2500_PLL); 419e57f7a3fSLendacky, Thomas 420e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, 421e57f7a3fSLendacky, Thomas phy_data->cdr_rate[XGBE_SPEED_2500]); 422e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, 423e57f7a3fSLendacky, Thomas phy_data->tx_amp[XGBE_SPEED_2500]); 424e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, 425e57f7a3fSLendacky, Thomas phy_data->blwc[XGBE_SPEED_2500]); 426e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, 427e57f7a3fSLendacky, Thomas phy_data->pq_skew[XGBE_SPEED_2500]); 428e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, 429e57f7a3fSLendacky, Thomas phy_data->dfe_tap_cfg[XGBE_SPEED_2500]); 430e57f7a3fSLendacky, Thomas XRXTX_IOWRITE(pdata, RXTX_REG22, 431e57f7a3fSLendacky, Thomas phy_data->dfe_tap_ena[XGBE_SPEED_2500]); 432e57f7a3fSLendacky, Thomas 433e57f7a3fSLendacky, Thomas xgbe_phy_complete_ratechange(pdata); 434e57f7a3fSLendacky, Thomas 435e57f7a3fSLendacky, Thomas netif_dbg(pdata, link, pdata->netdev, "2.5GbE KX mode set\n"); 436e57f7a3fSLendacky, Thomas } 437e57f7a3fSLendacky, Thomas 438e57f7a3fSLendacky, Thomas static void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) 439e57f7a3fSLendacky, Thomas { 440e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 441e57f7a3fSLendacky, Thomas unsigned int reg; 442e57f7a3fSLendacky, Thomas 443e57f7a3fSLendacky, Thomas /* Set PCS to KX/1G speed */ 444e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 445e57f7a3fSLendacky, Thomas reg &= ~MDIO_PCS_CTRL2_TYPE; 446e57f7a3fSLendacky, Thomas reg |= MDIO_PCS_CTRL2_10GBX; 447e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); 448e57f7a3fSLendacky, Thomas 449e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 450e57f7a3fSLendacky, Thomas reg &= ~MDIO_CTRL1_SPEEDSEL; 451e57f7a3fSLendacky, Thomas reg |= MDIO_CTRL1_SPEED1G; 452e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 453e57f7a3fSLendacky, Thomas 454e57f7a3fSLendacky, Thomas xgbe_phy_pcs_power_cycle(pdata); 455e57f7a3fSLendacky, Thomas 456e57f7a3fSLendacky, Thomas /* Set SerDes to 1G speed */ 457e57f7a3fSLendacky, Thomas xgbe_phy_start_ratechange(pdata); 458e57f7a3fSLendacky, Thomas 459e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE); 460e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD); 461e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL); 462e57f7a3fSLendacky, Thomas 463e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, 464e57f7a3fSLendacky, Thomas phy_data->cdr_rate[XGBE_SPEED_1000]); 465e57f7a3fSLendacky, Thomas XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, 466e57f7a3fSLendacky, Thomas phy_data->tx_amp[XGBE_SPEED_1000]); 467e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, 468e57f7a3fSLendacky, Thomas phy_data->blwc[XGBE_SPEED_1000]); 469e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, 470e57f7a3fSLendacky, Thomas phy_data->pq_skew[XGBE_SPEED_1000]); 471e57f7a3fSLendacky, Thomas XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, 472e57f7a3fSLendacky, Thomas phy_data->dfe_tap_cfg[XGBE_SPEED_1000]); 473e57f7a3fSLendacky, Thomas XRXTX_IOWRITE(pdata, RXTX_REG22, 474e57f7a3fSLendacky, Thomas phy_data->dfe_tap_ena[XGBE_SPEED_1000]); 475e57f7a3fSLendacky, Thomas 476e57f7a3fSLendacky, Thomas xgbe_phy_complete_ratechange(pdata); 477e57f7a3fSLendacky, Thomas 478e57f7a3fSLendacky, Thomas netif_dbg(pdata, link, pdata->netdev, "1GbE KX mode set\n"); 479e57f7a3fSLendacky, Thomas } 480e57f7a3fSLendacky, Thomas 481e57f7a3fSLendacky, Thomas static enum xgbe_mode xgbe_phy_cur_mode(struct xgbe_prv_data *pdata) 482e57f7a3fSLendacky, Thomas { 483e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 484e57f7a3fSLendacky, Thomas enum xgbe_mode mode; 485e57f7a3fSLendacky, Thomas unsigned int reg; 486e57f7a3fSLendacky, Thomas 487e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 488e57f7a3fSLendacky, Thomas reg &= MDIO_PCS_CTRL2_TYPE; 489e57f7a3fSLendacky, Thomas 490e57f7a3fSLendacky, Thomas if (reg == MDIO_PCS_CTRL2_10GBR) { 491e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KR; 492e57f7a3fSLendacky, Thomas } else { 493e57f7a3fSLendacky, Thomas if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 494e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KX_2500; 495e57f7a3fSLendacky, Thomas else 496e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KX_1000; 497e57f7a3fSLendacky, Thomas } 498e57f7a3fSLendacky, Thomas 499e57f7a3fSLendacky, Thomas return mode; 500e57f7a3fSLendacky, Thomas } 501e57f7a3fSLendacky, Thomas 502e57f7a3fSLendacky, Thomas static enum xgbe_mode xgbe_phy_switch_mode(struct xgbe_prv_data *pdata) 503e57f7a3fSLendacky, Thomas { 504e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 505e57f7a3fSLendacky, Thomas enum xgbe_mode mode; 506e57f7a3fSLendacky, Thomas 507e57f7a3fSLendacky, Thomas /* If we are in KR switch to KX, and vice-versa */ 508e57f7a3fSLendacky, Thomas if (xgbe_phy_cur_mode(pdata) == XGBE_MODE_KR) { 509e57f7a3fSLendacky, Thomas if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 510e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KX_2500; 511e57f7a3fSLendacky, Thomas else 512e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KX_1000; 513e57f7a3fSLendacky, Thomas } else { 514e57f7a3fSLendacky, Thomas mode = XGBE_MODE_KR; 515e57f7a3fSLendacky, Thomas } 516e57f7a3fSLendacky, Thomas 517e57f7a3fSLendacky, Thomas return mode; 518e57f7a3fSLendacky, Thomas } 519e57f7a3fSLendacky, Thomas 520e57f7a3fSLendacky, Thomas static enum xgbe_mode xgbe_phy_get_mode(struct xgbe_prv_data *pdata, 521e57f7a3fSLendacky, Thomas int speed) 522e57f7a3fSLendacky, Thomas { 523e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 524e57f7a3fSLendacky, Thomas 525e57f7a3fSLendacky, Thomas switch (speed) { 526e57f7a3fSLendacky, Thomas case SPEED_1000: 527e57f7a3fSLendacky, Thomas return (phy_data->speed_set == XGBE_SPEEDSET_1000_10000) 528e57f7a3fSLendacky, Thomas ? XGBE_MODE_KX_1000 : XGBE_MODE_UNKNOWN; 529e57f7a3fSLendacky, Thomas case SPEED_2500: 530e57f7a3fSLendacky, Thomas return (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 531e57f7a3fSLendacky, Thomas ? XGBE_MODE_KX_2500 : XGBE_MODE_UNKNOWN; 532e57f7a3fSLendacky, Thomas case SPEED_10000: 533e57f7a3fSLendacky, Thomas return XGBE_MODE_KR; 534e57f7a3fSLendacky, Thomas default: 535e57f7a3fSLendacky, Thomas return XGBE_MODE_UNKNOWN; 536e57f7a3fSLendacky, Thomas } 537e57f7a3fSLendacky, Thomas } 538e57f7a3fSLendacky, Thomas 539e57f7a3fSLendacky, Thomas static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 540e57f7a3fSLendacky, Thomas { 541e57f7a3fSLendacky, Thomas switch (mode) { 542e57f7a3fSLendacky, Thomas case XGBE_MODE_KX_1000: 543e57f7a3fSLendacky, Thomas xgbe_phy_kx_1000_mode(pdata); 544e57f7a3fSLendacky, Thomas break; 545e57f7a3fSLendacky, Thomas case XGBE_MODE_KX_2500: 546e57f7a3fSLendacky, Thomas xgbe_phy_kx_2500_mode(pdata); 547e57f7a3fSLendacky, Thomas break; 548e57f7a3fSLendacky, Thomas case XGBE_MODE_KR: 549e57f7a3fSLendacky, Thomas xgbe_phy_kr_mode(pdata); 550e57f7a3fSLendacky, Thomas break; 551e57f7a3fSLendacky, Thomas default: 552e57f7a3fSLendacky, Thomas break; 553e57f7a3fSLendacky, Thomas } 554e57f7a3fSLendacky, Thomas } 555e57f7a3fSLendacky, Thomas 556e57f7a3fSLendacky, Thomas static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, 557e57f7a3fSLendacky, Thomas enum xgbe_mode mode, u32 advert) 558e57f7a3fSLendacky, Thomas { 559e57f7a3fSLendacky, Thomas if (pdata->phy.autoneg == AUTONEG_ENABLE) { 560e57f7a3fSLendacky, Thomas if (pdata->phy.advertising & advert) 561e57f7a3fSLendacky, Thomas return true; 562e57f7a3fSLendacky, Thomas } else { 563e57f7a3fSLendacky, Thomas enum xgbe_mode cur_mode; 564e57f7a3fSLendacky, Thomas 565e57f7a3fSLendacky, Thomas cur_mode = xgbe_phy_get_mode(pdata, pdata->phy.speed); 566e57f7a3fSLendacky, Thomas if (cur_mode == mode) 567e57f7a3fSLendacky, Thomas return true; 568e57f7a3fSLendacky, Thomas } 569e57f7a3fSLendacky, Thomas 570e57f7a3fSLendacky, Thomas return false; 571e57f7a3fSLendacky, Thomas } 572e57f7a3fSLendacky, Thomas 573e57f7a3fSLendacky, Thomas static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 574e57f7a3fSLendacky, Thomas { 575e57f7a3fSLendacky, Thomas switch (mode) { 576e57f7a3fSLendacky, Thomas case XGBE_MODE_KX_1000: 577e57f7a3fSLendacky, Thomas return xgbe_phy_check_mode(pdata, mode, 578e57f7a3fSLendacky, Thomas ADVERTISED_1000baseKX_Full); 579e57f7a3fSLendacky, Thomas case XGBE_MODE_KX_2500: 580e57f7a3fSLendacky, Thomas return xgbe_phy_check_mode(pdata, mode, 581e57f7a3fSLendacky, Thomas ADVERTISED_2500baseX_Full); 582e57f7a3fSLendacky, Thomas case XGBE_MODE_KR: 583e57f7a3fSLendacky, Thomas return xgbe_phy_check_mode(pdata, mode, 584e57f7a3fSLendacky, Thomas ADVERTISED_10000baseKR_Full); 585e57f7a3fSLendacky, Thomas default: 586e57f7a3fSLendacky, Thomas return false; 587e57f7a3fSLendacky, Thomas } 588e57f7a3fSLendacky, Thomas } 589e57f7a3fSLendacky, Thomas 590e57f7a3fSLendacky, Thomas static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) 591e57f7a3fSLendacky, Thomas { 592e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data = pdata->phy_data; 593e57f7a3fSLendacky, Thomas 594e57f7a3fSLendacky, Thomas switch (speed) { 595e57f7a3fSLendacky, Thomas case SPEED_1000: 596e57f7a3fSLendacky, Thomas if (phy_data->speed_set != XGBE_SPEEDSET_1000_10000) 597e57f7a3fSLendacky, Thomas return false; 598e57f7a3fSLendacky, Thomas return true; 599e57f7a3fSLendacky, Thomas case SPEED_2500: 600e57f7a3fSLendacky, Thomas if (phy_data->speed_set != XGBE_SPEEDSET_2500_10000) 601e57f7a3fSLendacky, Thomas return false; 602e57f7a3fSLendacky, Thomas return true; 603e57f7a3fSLendacky, Thomas case SPEED_10000: 604e57f7a3fSLendacky, Thomas return true; 605e57f7a3fSLendacky, Thomas default: 606e57f7a3fSLendacky, Thomas return false; 607e57f7a3fSLendacky, Thomas } 608e57f7a3fSLendacky, Thomas } 609e57f7a3fSLendacky, Thomas 610e57f7a3fSLendacky, Thomas static int xgbe_phy_link_status(struct xgbe_prv_data *pdata) 611e57f7a3fSLendacky, Thomas { 612e57f7a3fSLendacky, Thomas unsigned int reg; 613e57f7a3fSLendacky, Thomas 614e57f7a3fSLendacky, Thomas /* Link status is latched low, so read once to clear 615e57f7a3fSLendacky, Thomas * and then read again to get current state 616e57f7a3fSLendacky, Thomas */ 617e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 618e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 619e57f7a3fSLendacky, Thomas 620e57f7a3fSLendacky, Thomas return (reg & MDIO_STAT1_LSTATUS) ? 1 : 0; 621e57f7a3fSLendacky, Thomas } 622e57f7a3fSLendacky, Thomas 623e57f7a3fSLendacky, Thomas static void xgbe_phy_stop(struct xgbe_prv_data *pdata) 624e57f7a3fSLendacky, Thomas { 625e57f7a3fSLendacky, Thomas /* Nothing uniquely required for stop */ 626e57f7a3fSLendacky, Thomas } 627e57f7a3fSLendacky, Thomas 628e57f7a3fSLendacky, Thomas static int xgbe_phy_start(struct xgbe_prv_data *pdata) 629e57f7a3fSLendacky, Thomas { 630e57f7a3fSLendacky, Thomas /* Nothing uniquely required for start */ 631e57f7a3fSLendacky, Thomas return 0; 632e57f7a3fSLendacky, Thomas } 633e57f7a3fSLendacky, Thomas 634e57f7a3fSLendacky, Thomas static int xgbe_phy_reset(struct xgbe_prv_data *pdata) 635e57f7a3fSLendacky, Thomas { 636e57f7a3fSLendacky, Thomas unsigned int reg, count; 637e57f7a3fSLendacky, Thomas 638e57f7a3fSLendacky, Thomas /* Perform a software reset of the PCS */ 639e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 640e57f7a3fSLendacky, Thomas reg |= MDIO_CTRL1_RESET; 641e57f7a3fSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 642e57f7a3fSLendacky, Thomas 643e57f7a3fSLendacky, Thomas count = 50; 644e57f7a3fSLendacky, Thomas do { 645e57f7a3fSLendacky, Thomas msleep(20); 646e57f7a3fSLendacky, Thomas reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 647e57f7a3fSLendacky, Thomas } while ((reg & MDIO_CTRL1_RESET) && --count); 648e57f7a3fSLendacky, Thomas 649e57f7a3fSLendacky, Thomas if (reg & MDIO_CTRL1_RESET) 650e57f7a3fSLendacky, Thomas return -ETIMEDOUT; 651e57f7a3fSLendacky, Thomas 652e57f7a3fSLendacky, Thomas return 0; 653e57f7a3fSLendacky, Thomas } 654e57f7a3fSLendacky, Thomas 655e57f7a3fSLendacky, Thomas static void xgbe_phy_exit(struct xgbe_prv_data *pdata) 656e57f7a3fSLendacky, Thomas { 657e57f7a3fSLendacky, Thomas /* Nothing uniquely required for exit */ 658e57f7a3fSLendacky, Thomas } 659e57f7a3fSLendacky, Thomas 660e57f7a3fSLendacky, Thomas static int xgbe_phy_init(struct xgbe_prv_data *pdata) 661e57f7a3fSLendacky, Thomas { 662e57f7a3fSLendacky, Thomas struct xgbe_phy_data *phy_data; 663e57f7a3fSLendacky, Thomas int ret; 664e57f7a3fSLendacky, Thomas 665e57f7a3fSLendacky, Thomas phy_data = devm_kzalloc(pdata->dev, sizeof(*phy_data), GFP_KERNEL); 666e57f7a3fSLendacky, Thomas if (!phy_data) 667e57f7a3fSLendacky, Thomas return -ENOMEM; 668e57f7a3fSLendacky, Thomas 669e57f7a3fSLendacky, Thomas /* Retrieve the PHY speedset */ 670e57f7a3fSLendacky, Thomas ret = device_property_read_u32(pdata->phy_dev, XGBE_SPEEDSET_PROPERTY, 671e57f7a3fSLendacky, Thomas &phy_data->speed_set); 672e57f7a3fSLendacky, Thomas if (ret) { 673e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 674e57f7a3fSLendacky, Thomas XGBE_SPEEDSET_PROPERTY); 675e57f7a3fSLendacky, Thomas return ret; 676e57f7a3fSLendacky, Thomas } 677e57f7a3fSLendacky, Thomas 678e57f7a3fSLendacky, Thomas switch (phy_data->speed_set) { 679e57f7a3fSLendacky, Thomas case XGBE_SPEEDSET_1000_10000: 680e57f7a3fSLendacky, Thomas case XGBE_SPEEDSET_2500_10000: 681e57f7a3fSLendacky, Thomas break; 682e57f7a3fSLendacky, Thomas default: 683e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 684e57f7a3fSLendacky, Thomas XGBE_SPEEDSET_PROPERTY); 685e57f7a3fSLendacky, Thomas return -EINVAL; 686e57f7a3fSLendacky, Thomas } 687e57f7a3fSLendacky, Thomas 688e57f7a3fSLendacky, Thomas /* Retrieve the PHY configuration properties */ 689e57f7a3fSLendacky, Thomas if (device_property_present(pdata->phy_dev, XGBE_BLWC_PROPERTY)) { 690e57f7a3fSLendacky, Thomas ret = device_property_read_u32_array(pdata->phy_dev, 691e57f7a3fSLendacky, Thomas XGBE_BLWC_PROPERTY, 692e57f7a3fSLendacky, Thomas phy_data->blwc, 693e57f7a3fSLendacky, Thomas XGBE_SPEEDS); 694e57f7a3fSLendacky, Thomas if (ret) { 695e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 696e57f7a3fSLendacky, Thomas XGBE_BLWC_PROPERTY); 697e57f7a3fSLendacky, Thomas return ret; 698e57f7a3fSLendacky, Thomas } 699e57f7a3fSLendacky, Thomas } else { 700e57f7a3fSLendacky, Thomas memcpy(phy_data->blwc, xgbe_phy_blwc, 701e57f7a3fSLendacky, Thomas sizeof(phy_data->blwc)); 702e57f7a3fSLendacky, Thomas } 703e57f7a3fSLendacky, Thomas 704e57f7a3fSLendacky, Thomas if (device_property_present(pdata->phy_dev, XGBE_CDR_RATE_PROPERTY)) { 705e57f7a3fSLendacky, Thomas ret = device_property_read_u32_array(pdata->phy_dev, 706e57f7a3fSLendacky, Thomas XGBE_CDR_RATE_PROPERTY, 707e57f7a3fSLendacky, Thomas phy_data->cdr_rate, 708e57f7a3fSLendacky, Thomas XGBE_SPEEDS); 709e57f7a3fSLendacky, Thomas if (ret) { 710e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 711e57f7a3fSLendacky, Thomas XGBE_CDR_RATE_PROPERTY); 712e57f7a3fSLendacky, Thomas return ret; 713e57f7a3fSLendacky, Thomas } 714e57f7a3fSLendacky, Thomas } else { 715e57f7a3fSLendacky, Thomas memcpy(phy_data->cdr_rate, xgbe_phy_cdr_rate, 716e57f7a3fSLendacky, Thomas sizeof(phy_data->cdr_rate)); 717e57f7a3fSLendacky, Thomas } 718e57f7a3fSLendacky, Thomas 719e57f7a3fSLendacky, Thomas if (device_property_present(pdata->phy_dev, XGBE_PQ_SKEW_PROPERTY)) { 720e57f7a3fSLendacky, Thomas ret = device_property_read_u32_array(pdata->phy_dev, 721e57f7a3fSLendacky, Thomas XGBE_PQ_SKEW_PROPERTY, 722e57f7a3fSLendacky, Thomas phy_data->pq_skew, 723e57f7a3fSLendacky, Thomas XGBE_SPEEDS); 724e57f7a3fSLendacky, Thomas if (ret) { 725e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 726e57f7a3fSLendacky, Thomas XGBE_PQ_SKEW_PROPERTY); 727e57f7a3fSLendacky, Thomas return ret; 728e57f7a3fSLendacky, Thomas } 729e57f7a3fSLendacky, Thomas } else { 730e57f7a3fSLendacky, Thomas memcpy(phy_data->pq_skew, xgbe_phy_pq_skew, 731e57f7a3fSLendacky, Thomas sizeof(phy_data->pq_skew)); 732e57f7a3fSLendacky, Thomas } 733e57f7a3fSLendacky, Thomas 734e57f7a3fSLendacky, Thomas if (device_property_present(pdata->phy_dev, XGBE_TX_AMP_PROPERTY)) { 735e57f7a3fSLendacky, Thomas ret = device_property_read_u32_array(pdata->phy_dev, 736e57f7a3fSLendacky, Thomas XGBE_TX_AMP_PROPERTY, 737e57f7a3fSLendacky, Thomas phy_data->tx_amp, 738e57f7a3fSLendacky, Thomas XGBE_SPEEDS); 739e57f7a3fSLendacky, Thomas if (ret) { 740e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 741e57f7a3fSLendacky, Thomas XGBE_TX_AMP_PROPERTY); 742e57f7a3fSLendacky, Thomas return ret; 743e57f7a3fSLendacky, Thomas } 744e57f7a3fSLendacky, Thomas } else { 745e57f7a3fSLendacky, Thomas memcpy(phy_data->tx_amp, xgbe_phy_tx_amp, 746e57f7a3fSLendacky, Thomas sizeof(phy_data->tx_amp)); 747e57f7a3fSLendacky, Thomas } 748e57f7a3fSLendacky, Thomas 749e57f7a3fSLendacky, Thomas if (device_property_present(pdata->phy_dev, XGBE_DFE_CFG_PROPERTY)) { 750e57f7a3fSLendacky, Thomas ret = device_property_read_u32_array(pdata->phy_dev, 751e57f7a3fSLendacky, Thomas XGBE_DFE_CFG_PROPERTY, 752e57f7a3fSLendacky, Thomas phy_data->dfe_tap_cfg, 753e57f7a3fSLendacky, Thomas XGBE_SPEEDS); 754e57f7a3fSLendacky, Thomas if (ret) { 755e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 756e57f7a3fSLendacky, Thomas XGBE_DFE_CFG_PROPERTY); 757e57f7a3fSLendacky, Thomas return ret; 758e57f7a3fSLendacky, Thomas } 759e57f7a3fSLendacky, Thomas } else { 760e57f7a3fSLendacky, Thomas memcpy(phy_data->dfe_tap_cfg, xgbe_phy_dfe_tap_cfg, 761e57f7a3fSLendacky, Thomas sizeof(phy_data->dfe_tap_cfg)); 762e57f7a3fSLendacky, Thomas } 763e57f7a3fSLendacky, Thomas 764e57f7a3fSLendacky, Thomas if (device_property_present(pdata->phy_dev, XGBE_DFE_ENA_PROPERTY)) { 765e57f7a3fSLendacky, Thomas ret = device_property_read_u32_array(pdata->phy_dev, 766e57f7a3fSLendacky, Thomas XGBE_DFE_ENA_PROPERTY, 767e57f7a3fSLendacky, Thomas phy_data->dfe_tap_ena, 768e57f7a3fSLendacky, Thomas XGBE_SPEEDS); 769e57f7a3fSLendacky, Thomas if (ret) { 770e57f7a3fSLendacky, Thomas dev_err(pdata->dev, "invalid %s property\n", 771e57f7a3fSLendacky, Thomas XGBE_DFE_ENA_PROPERTY); 772e57f7a3fSLendacky, Thomas return ret; 773e57f7a3fSLendacky, Thomas } 774e57f7a3fSLendacky, Thomas } else { 775e57f7a3fSLendacky, Thomas memcpy(phy_data->dfe_tap_ena, xgbe_phy_dfe_tap_ena, 776e57f7a3fSLendacky, Thomas sizeof(phy_data->dfe_tap_ena)); 777e57f7a3fSLendacky, Thomas } 778e57f7a3fSLendacky, Thomas 779e57f7a3fSLendacky, Thomas /* Initialize supported features */ 780e57f7a3fSLendacky, Thomas pdata->phy.supported = SUPPORTED_Autoneg; 781e57f7a3fSLendacky, Thomas pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; 782e57f7a3fSLendacky, Thomas pdata->phy.supported |= SUPPORTED_Backplane; 783e57f7a3fSLendacky, Thomas pdata->phy.supported |= SUPPORTED_10000baseKR_Full; 784e57f7a3fSLendacky, Thomas switch (phy_data->speed_set) { 785e57f7a3fSLendacky, Thomas case XGBE_SPEEDSET_1000_10000: 786e57f7a3fSLendacky, Thomas pdata->phy.supported |= SUPPORTED_1000baseKX_Full; 787e57f7a3fSLendacky, Thomas break; 788e57f7a3fSLendacky, Thomas case XGBE_SPEEDSET_2500_10000: 789e57f7a3fSLendacky, Thomas pdata->phy.supported |= SUPPORTED_2500baseX_Full; 790e57f7a3fSLendacky, Thomas break; 791e57f7a3fSLendacky, Thomas } 792e57f7a3fSLendacky, Thomas 793e57f7a3fSLendacky, Thomas if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 794e57f7a3fSLendacky, Thomas pdata->phy.supported |= SUPPORTED_10000baseR_FEC; 795e57f7a3fSLendacky, Thomas 796e57f7a3fSLendacky, Thomas pdata->phy_data = phy_data; 797e57f7a3fSLendacky, Thomas 798e57f7a3fSLendacky, Thomas return 0; 799e57f7a3fSLendacky, Thomas } 800e57f7a3fSLendacky, Thomas 801e57f7a3fSLendacky, Thomas void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if) 802e57f7a3fSLendacky, Thomas { 803e57f7a3fSLendacky, Thomas struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; 804e57f7a3fSLendacky, Thomas 805e57f7a3fSLendacky, Thomas phy_impl->init = xgbe_phy_init; 806e57f7a3fSLendacky, Thomas phy_impl->exit = xgbe_phy_exit; 807e57f7a3fSLendacky, Thomas 808e57f7a3fSLendacky, Thomas phy_impl->reset = xgbe_phy_reset; 809e57f7a3fSLendacky, Thomas phy_impl->start = xgbe_phy_start; 810e57f7a3fSLendacky, Thomas phy_impl->stop = xgbe_phy_stop; 811e57f7a3fSLendacky, Thomas 812e57f7a3fSLendacky, Thomas phy_impl->link_status = xgbe_phy_link_status; 813e57f7a3fSLendacky, Thomas 814e57f7a3fSLendacky, Thomas phy_impl->valid_speed = xgbe_phy_valid_speed; 815e57f7a3fSLendacky, Thomas 816e57f7a3fSLendacky, Thomas phy_impl->use_mode = xgbe_phy_use_mode; 817e57f7a3fSLendacky, Thomas phy_impl->set_mode = xgbe_phy_set_mode; 818e57f7a3fSLendacky, Thomas phy_impl->get_mode = xgbe_phy_get_mode; 819e57f7a3fSLendacky, Thomas phy_impl->switch_mode = xgbe_phy_switch_mode; 820e57f7a3fSLendacky, Thomas phy_impl->cur_mode = xgbe_phy_cur_mode; 821e57f7a3fSLendacky, Thomas 822*a64def41SLendacky, Thomas phy_impl->an_mode = xgbe_phy_an_mode; 823*a64def41SLendacky, Thomas 824e57f7a3fSLendacky, Thomas phy_impl->an_outcome = xgbe_phy_an_outcome; 825e57f7a3fSLendacky, Thomas 826e57f7a3fSLendacky, Thomas phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; 827e57f7a3fSLendacky, Thomas phy_impl->kr_training_post = xgbe_phy_kr_training_post; 828e57f7a3fSLendacky, Thomas } 829