18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * AMD 10Gb Ethernet driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is available to you under your choice of the following two 58c2ecf20Sopenharmony_ci * licenses: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * License 1: GPLv2 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2016 Advanced Micro Devices, Inc. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 138c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at 148c2ecf20Sopenharmony_ci * your option) any later version. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 198c2ecf20Sopenharmony_ci * General Public License for more details. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 228c2ecf20Sopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 258c2ecf20Sopenharmony_ci * permission notice: 268c2ecf20Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 278c2ecf20Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 288c2ecf20Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 298c2ecf20Sopenharmony_ci * and you. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 328c2ecf20Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 338c2ecf20Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 348c2ecf20Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 358c2ecf20Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 368c2ecf20Sopenharmony_ci * without restriction, including without limitation the rights to use, 378c2ecf20Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 388c2ecf20Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 398c2ecf20Sopenharmony_ci * to do so, subject to the following conditions: 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included 428c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 458c2ecf20Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 468c2ecf20Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 478c2ecf20Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 488c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 498c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 508c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 518c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 528c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 538c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 548c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * License 2: Modified BSD 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Copyright (c) 2016 Advanced Micro Devices, Inc. 608c2ecf20Sopenharmony_ci * All rights reserved. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 638c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 648c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 658c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 668c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 678c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 688c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 698c2ecf20Sopenharmony_ci * * Neither the name of Advanced Micro Devices, Inc. nor the 708c2ecf20Sopenharmony_ci * names of its contributors may be used to endorse or promote products 718c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 748c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 758c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 768c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 778c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 788c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 798c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 808c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 818c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 828c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 858c2ecf20Sopenharmony_ci * permission notice: 868c2ecf20Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 878c2ecf20Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 888c2ecf20Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 898c2ecf20Sopenharmony_ci * and you. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 928c2ecf20Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 938c2ecf20Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 948c2ecf20Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 958c2ecf20Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 968c2ecf20Sopenharmony_ci * without restriction, including without limitation the rights to use, 978c2ecf20Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 988c2ecf20Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 998c2ecf20Sopenharmony_ci * to do so, subject to the following conditions: 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included 1028c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 1058c2ecf20Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1068c2ecf20Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 1078c2ecf20Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 1088c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1098c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1108c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1118c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1128c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1138c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1148c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#include <linux/module.h> 1188c2ecf20Sopenharmony_ci#include <linux/kmod.h> 1198c2ecf20Sopenharmony_ci#include <linux/device.h> 1208c2ecf20Sopenharmony_ci#include <linux/property.h> 1218c2ecf20Sopenharmony_ci#include <linux/mdio.h> 1228c2ecf20Sopenharmony_ci#include <linux/phy.h> 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#include "xgbe.h" 1258c2ecf20Sopenharmony_ci#include "xgbe-common.h" 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define XGBE_BLWC_PROPERTY "amd,serdes-blwc" 1288c2ecf20Sopenharmony_ci#define XGBE_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" 1298c2ecf20Sopenharmony_ci#define XGBE_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" 1308c2ecf20Sopenharmony_ci#define XGBE_TX_AMP_PROPERTY "amd,serdes-tx-amp" 1318c2ecf20Sopenharmony_ci#define XGBE_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config" 1328c2ecf20Sopenharmony_ci#define XGBE_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable" 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* Default SerDes settings */ 1358c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_BLWC 1 1368c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_CDR 0x2 1378c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_PLL 0x0 1388c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_PQ 0xa 1398c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_RATE 0x3 1408c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_TXAMP 0xf 1418c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_WORD 0x1 1428c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_DFE_TAP_CONFIG 0x3 1438c2ecf20Sopenharmony_ci#define XGBE_SPEED_1000_DFE_TAP_ENABLE 0x0 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_BLWC 1 1468c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_CDR 0x2 1478c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_PLL 0x0 1488c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_PQ 0xa 1498c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_RATE 0x1 1508c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_TXAMP 0xf 1518c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_WORD 0x1 1528c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_DFE_TAP_CONFIG 0x3 1538c2ecf20Sopenharmony_ci#define XGBE_SPEED_2500_DFE_TAP_ENABLE 0x0 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_BLWC 0 1568c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_CDR 0x7 1578c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_PLL 0x1 1588c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_PQ 0x12 1598c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_RATE 0x0 1608c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_TXAMP 0xa 1618c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_WORD 0x7 1628c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_DFE_TAP_CONFIG 0x1 1638c2ecf20Sopenharmony_ci#define XGBE_SPEED_10000_DFE_TAP_ENABLE 0x7f 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Rate-change complete wait/retry count */ 1668c2ecf20Sopenharmony_ci#define XGBE_RATECHANGE_COUNT 500 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic const u32 xgbe_phy_blwc[] = { 1698c2ecf20Sopenharmony_ci XGBE_SPEED_1000_BLWC, 1708c2ecf20Sopenharmony_ci XGBE_SPEED_2500_BLWC, 1718c2ecf20Sopenharmony_ci XGBE_SPEED_10000_BLWC, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const u32 xgbe_phy_cdr_rate[] = { 1758c2ecf20Sopenharmony_ci XGBE_SPEED_1000_CDR, 1768c2ecf20Sopenharmony_ci XGBE_SPEED_2500_CDR, 1778c2ecf20Sopenharmony_ci XGBE_SPEED_10000_CDR, 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic const u32 xgbe_phy_pq_skew[] = { 1818c2ecf20Sopenharmony_ci XGBE_SPEED_1000_PQ, 1828c2ecf20Sopenharmony_ci XGBE_SPEED_2500_PQ, 1838c2ecf20Sopenharmony_ci XGBE_SPEED_10000_PQ, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic const u32 xgbe_phy_tx_amp[] = { 1878c2ecf20Sopenharmony_ci XGBE_SPEED_1000_TXAMP, 1888c2ecf20Sopenharmony_ci XGBE_SPEED_2500_TXAMP, 1898c2ecf20Sopenharmony_ci XGBE_SPEED_10000_TXAMP, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic const u32 xgbe_phy_dfe_tap_cfg[] = { 1938c2ecf20Sopenharmony_ci XGBE_SPEED_1000_DFE_TAP_CONFIG, 1948c2ecf20Sopenharmony_ci XGBE_SPEED_2500_DFE_TAP_CONFIG, 1958c2ecf20Sopenharmony_ci XGBE_SPEED_10000_DFE_TAP_CONFIG, 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic const u32 xgbe_phy_dfe_tap_ena[] = { 1998c2ecf20Sopenharmony_ci XGBE_SPEED_1000_DFE_TAP_ENABLE, 2008c2ecf20Sopenharmony_ci XGBE_SPEED_2500_DFE_TAP_ENABLE, 2018c2ecf20Sopenharmony_ci XGBE_SPEED_10000_DFE_TAP_ENABLE, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistruct xgbe_phy_data { 2058c2ecf20Sopenharmony_ci /* 1000/10000 vs 2500/10000 indicator */ 2068c2ecf20Sopenharmony_ci unsigned int speed_set; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* SerDes UEFI configurable settings. 2098c2ecf20Sopenharmony_ci * Switching between modes/speeds requires new values for some 2108c2ecf20Sopenharmony_ci * SerDes settings. The values can be supplied as device 2118c2ecf20Sopenharmony_ci * properties in array format. The first array entry is for 2128c2ecf20Sopenharmony_ci * 1GbE, second for 2.5GbE and third for 10GbE 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci u32 blwc[XGBE_SPEEDS]; 2158c2ecf20Sopenharmony_ci u32 cdr_rate[XGBE_SPEEDS]; 2168c2ecf20Sopenharmony_ci u32 pq_skew[XGBE_SPEEDS]; 2178c2ecf20Sopenharmony_ci u32 tx_amp[XGBE_SPEEDS]; 2188c2ecf20Sopenharmony_ci u32 dfe_tap_cfg[XGBE_SPEEDS]; 2198c2ecf20Sopenharmony_ci u32 dfe_tap_ena[XGBE_SPEEDS]; 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 2358c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 2368c2ecf20Sopenharmony_ci enum xgbe_mode mode; 2378c2ecf20Sopenharmony_ci unsigned int ad_reg, lp_reg; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Autoneg); 2408c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Backplane); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 1 */ 2438c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); 2448c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); 2458c2ecf20Sopenharmony_ci if (lp_reg & 0x400) 2468c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Pause); 2478c2ecf20Sopenharmony_ci if (lp_reg & 0x800) 2488c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, Asym_Pause); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (pdata->phy.pause_autoneg) { 2518c2ecf20Sopenharmony_ci /* Set flow control based on auto-negotiation result */ 2528c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 0; 2538c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (ad_reg & lp_reg & 0x400) { 2568c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 2578c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 2588c2ecf20Sopenharmony_ci } else if (ad_reg & lp_reg & 0x800) { 2598c2ecf20Sopenharmony_ci if (ad_reg & 0x400) 2608c2ecf20Sopenharmony_ci pdata->phy.rx_pause = 1; 2618c2ecf20Sopenharmony_ci else if (lp_reg & 0x400) 2628c2ecf20Sopenharmony_ci pdata->phy.tx_pause = 1; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 2 */ 2678c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); 2688c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); 2698c2ecf20Sopenharmony_ci if (lp_reg & 0x80) 2708c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseKR_Full); 2718c2ecf20Sopenharmony_ci if (lp_reg & 0x20) { 2728c2ecf20Sopenharmony_ci if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 2738c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 2500baseX_Full); 2748c2ecf20Sopenharmony_ci else 2758c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 1000baseKX_Full); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci ad_reg &= lp_reg; 2798c2ecf20Sopenharmony_ci if (ad_reg & 0x80) { 2808c2ecf20Sopenharmony_ci mode = XGBE_MODE_KR; 2818c2ecf20Sopenharmony_ci } else if (ad_reg & 0x20) { 2828c2ecf20Sopenharmony_ci if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 2838c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_2500; 2848c2ecf20Sopenharmony_ci else 2858c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_1000; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci mode = XGBE_MODE_UNKNOWN; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Compare Advertisement and Link Partner register 3 */ 2918c2ecf20Sopenharmony_ci ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); 2928c2ecf20Sopenharmony_ci lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); 2938c2ecf20Sopenharmony_ci if (lp_reg & 0xc000) 2948c2ecf20Sopenharmony_ci XGBE_SET_LP_ADV(lks, 10000baseR_FEC); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return mode; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata, 3008c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *dlks) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *slks = &pdata->phy.lks; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci XGBE_LM_COPY(dlks, advertising, slks, advertising); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int xgbe_phy_an_config(struct xgbe_prv_data *pdata) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci /* Nothing uniquely required for an configuration */ 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci return XGBE_AN_MODE_CL73; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void xgbe_phy_pcs_power_cycle(struct xgbe_prv_data *pdata) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci unsigned int reg; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci reg |= MDIO_CTRL1_LPOWER; 3258c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci usleep_range(75, 100); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci reg &= ~MDIO_CTRL1_LPOWER; 3308c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void xgbe_phy_start_ratechange(struct xgbe_prv_data *pdata) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci /* Assert Rx and Tx ratechange */ 3368c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void xgbe_phy_complete_ratechange(struct xgbe_prv_data *pdata) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci unsigned int wait; 3428c2ecf20Sopenharmony_ci u16 status; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Release Rx and Tx ratechange */ 3458c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Wait for Rx and Tx ready */ 3488c2ecf20Sopenharmony_ci wait = XGBE_RATECHANGE_COUNT; 3498c2ecf20Sopenharmony_ci while (wait--) { 3508c2ecf20Sopenharmony_ci usleep_range(50, 75); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci status = XSIR0_IOREAD(pdata, SIR0_STATUS); 3538c2ecf20Sopenharmony_ci if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && 3548c2ecf20Sopenharmony_ci XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) 3558c2ecf20Sopenharmony_ci goto rx_reset; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "SerDes rx/tx not ready (%#hx)\n", 3598c2ecf20Sopenharmony_ci status); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cirx_reset: 3628c2ecf20Sopenharmony_ci /* Perform Rx reset for the DFE changes */ 3638c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 0); 3648c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 1); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 3708c2ecf20Sopenharmony_ci unsigned int reg; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* Set PCS to KR/10G speed */ 3738c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 3748c2ecf20Sopenharmony_ci reg &= ~MDIO_PCS_CTRL2_TYPE; 3758c2ecf20Sopenharmony_ci reg |= MDIO_PCS_CTRL2_10GBR; 3768c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 3798c2ecf20Sopenharmony_ci reg &= ~MDIO_CTRL1_SPEEDSEL; 3808c2ecf20Sopenharmony_ci reg |= MDIO_CTRL1_SPEED10G; 3818c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci xgbe_phy_pcs_power_cycle(pdata); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Set SerDes to 10G speed */ 3868c2ecf20Sopenharmony_ci xgbe_phy_start_ratechange(pdata); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_10000_RATE); 3898c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_10000_WORD); 3908c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_10000_PLL); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, 3938c2ecf20Sopenharmony_ci phy_data->cdr_rate[XGBE_SPEED_10000]); 3948c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, 3958c2ecf20Sopenharmony_ci phy_data->tx_amp[XGBE_SPEED_10000]); 3968c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, 3978c2ecf20Sopenharmony_ci phy_data->blwc[XGBE_SPEED_10000]); 3988c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, 3998c2ecf20Sopenharmony_ci phy_data->pq_skew[XGBE_SPEED_10000]); 4008c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, 4018c2ecf20Sopenharmony_ci phy_data->dfe_tap_cfg[XGBE_SPEED_10000]); 4028c2ecf20Sopenharmony_ci XRXTX_IOWRITE(pdata, RXTX_REG22, 4038c2ecf20Sopenharmony_ci phy_data->dfe_tap_ena[XGBE_SPEED_10000]); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci xgbe_phy_complete_ratechange(pdata); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "10GbE KR mode set\n"); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 4138c2ecf20Sopenharmony_ci unsigned int reg; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Set PCS to KX/1G speed */ 4168c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 4178c2ecf20Sopenharmony_ci reg &= ~MDIO_PCS_CTRL2_TYPE; 4188c2ecf20Sopenharmony_ci reg |= MDIO_PCS_CTRL2_10GBX; 4198c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 4228c2ecf20Sopenharmony_ci reg &= ~MDIO_CTRL1_SPEEDSEL; 4238c2ecf20Sopenharmony_ci reg |= MDIO_CTRL1_SPEED1G; 4248c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci xgbe_phy_pcs_power_cycle(pdata); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Set SerDes to 2.5G speed */ 4298c2ecf20Sopenharmony_ci xgbe_phy_start_ratechange(pdata); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_2500_RATE); 4328c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_2500_WORD); 4338c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_2500_PLL); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, 4368c2ecf20Sopenharmony_ci phy_data->cdr_rate[XGBE_SPEED_2500]); 4378c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, 4388c2ecf20Sopenharmony_ci phy_data->tx_amp[XGBE_SPEED_2500]); 4398c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, 4408c2ecf20Sopenharmony_ci phy_data->blwc[XGBE_SPEED_2500]); 4418c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, 4428c2ecf20Sopenharmony_ci phy_data->pq_skew[XGBE_SPEED_2500]); 4438c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, 4448c2ecf20Sopenharmony_ci phy_data->dfe_tap_cfg[XGBE_SPEED_2500]); 4458c2ecf20Sopenharmony_ci XRXTX_IOWRITE(pdata, RXTX_REG22, 4468c2ecf20Sopenharmony_ci phy_data->dfe_tap_ena[XGBE_SPEED_2500]); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci xgbe_phy_complete_ratechange(pdata); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "2.5GbE KX mode set\n"); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 4568c2ecf20Sopenharmony_ci unsigned int reg; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Set PCS to KX/1G speed */ 4598c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 4608c2ecf20Sopenharmony_ci reg &= ~MDIO_PCS_CTRL2_TYPE; 4618c2ecf20Sopenharmony_ci reg |= MDIO_PCS_CTRL2_10GBX; 4628c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 4658c2ecf20Sopenharmony_ci reg &= ~MDIO_CTRL1_SPEEDSEL; 4668c2ecf20Sopenharmony_ci reg |= MDIO_CTRL1_SPEED1G; 4678c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci xgbe_phy_pcs_power_cycle(pdata); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Set SerDes to 1G speed */ 4728c2ecf20Sopenharmony_ci xgbe_phy_start_ratechange(pdata); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE); 4758c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD); 4768c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, 4798c2ecf20Sopenharmony_ci phy_data->cdr_rate[XGBE_SPEED_1000]); 4808c2ecf20Sopenharmony_ci XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, 4818c2ecf20Sopenharmony_ci phy_data->tx_amp[XGBE_SPEED_1000]); 4828c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, 4838c2ecf20Sopenharmony_ci phy_data->blwc[XGBE_SPEED_1000]); 4848c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, 4858c2ecf20Sopenharmony_ci phy_data->pq_skew[XGBE_SPEED_1000]); 4868c2ecf20Sopenharmony_ci XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, 4878c2ecf20Sopenharmony_ci phy_data->dfe_tap_cfg[XGBE_SPEED_1000]); 4888c2ecf20Sopenharmony_ci XRXTX_IOWRITE(pdata, RXTX_REG22, 4898c2ecf20Sopenharmony_ci phy_data->dfe_tap_ena[XGBE_SPEED_1000]); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci xgbe_phy_complete_ratechange(pdata); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci netif_dbg(pdata, link, pdata->netdev, "1GbE KX mode set\n"); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_cur_mode(struct xgbe_prv_data *pdata) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 4998c2ecf20Sopenharmony_ci enum xgbe_mode mode; 5008c2ecf20Sopenharmony_ci unsigned int reg; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); 5038c2ecf20Sopenharmony_ci reg &= MDIO_PCS_CTRL2_TYPE; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (reg == MDIO_PCS_CTRL2_10GBR) { 5068c2ecf20Sopenharmony_ci mode = XGBE_MODE_KR; 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 5098c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_2500; 5108c2ecf20Sopenharmony_ci else 5118c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_1000; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return mode; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_switch_mode(struct xgbe_prv_data *pdata) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 5208c2ecf20Sopenharmony_ci enum xgbe_mode mode; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* If we are in KR switch to KX, and vice-versa */ 5238c2ecf20Sopenharmony_ci if (xgbe_phy_cur_mode(pdata) == XGBE_MODE_KR) { 5248c2ecf20Sopenharmony_ci if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 5258c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_2500; 5268c2ecf20Sopenharmony_ci else 5278c2ecf20Sopenharmony_ci mode = XGBE_MODE_KX_1000; 5288c2ecf20Sopenharmony_ci } else { 5298c2ecf20Sopenharmony_ci mode = XGBE_MODE_KR; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return mode; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic enum xgbe_mode xgbe_phy_get_mode(struct xgbe_prv_data *pdata, 5368c2ecf20Sopenharmony_ci int speed) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci switch (speed) { 5418c2ecf20Sopenharmony_ci case SPEED_1000: 5428c2ecf20Sopenharmony_ci return (phy_data->speed_set == XGBE_SPEEDSET_1000_10000) 5438c2ecf20Sopenharmony_ci ? XGBE_MODE_KX_1000 : XGBE_MODE_UNKNOWN; 5448c2ecf20Sopenharmony_ci case SPEED_2500: 5458c2ecf20Sopenharmony_ci return (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) 5468c2ecf20Sopenharmony_ci ? XGBE_MODE_KX_2500 : XGBE_MODE_UNKNOWN; 5478c2ecf20Sopenharmony_ci case SPEED_10000: 5488c2ecf20Sopenharmony_ci return XGBE_MODE_KR; 5498c2ecf20Sopenharmony_ci default: 5508c2ecf20Sopenharmony_ci return XGBE_MODE_UNKNOWN; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci switch (mode) { 5578c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 5588c2ecf20Sopenharmony_ci xgbe_phy_kx_1000_mode(pdata); 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 5618c2ecf20Sopenharmony_ci xgbe_phy_kx_2500_mode(pdata); 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 5648c2ecf20Sopenharmony_ci xgbe_phy_kr_mode(pdata); 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci default: 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, 5728c2ecf20Sopenharmony_ci enum xgbe_mode mode, bool advert) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci if (pdata->phy.autoneg == AUTONEG_ENABLE) { 5758c2ecf20Sopenharmony_ci return advert; 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci enum xgbe_mode cur_mode; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci cur_mode = xgbe_phy_get_mode(pdata, pdata->phy.speed); 5808c2ecf20Sopenharmony_ci if (cur_mode == mode) 5818c2ecf20Sopenharmony_ci return true; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return false; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci switch (mode) { 5928c2ecf20Sopenharmony_ci case XGBE_MODE_KX_1000: 5938c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 5948c2ecf20Sopenharmony_ci XGBE_ADV(lks, 1000baseKX_Full)); 5958c2ecf20Sopenharmony_ci case XGBE_MODE_KX_2500: 5968c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 5978c2ecf20Sopenharmony_ci XGBE_ADV(lks, 2500baseX_Full)); 5988c2ecf20Sopenharmony_ci case XGBE_MODE_KR: 5998c2ecf20Sopenharmony_ci return xgbe_phy_check_mode(pdata, mode, 6008c2ecf20Sopenharmony_ci XGBE_ADV(lks, 10000baseKR_Full)); 6018c2ecf20Sopenharmony_ci default: 6028c2ecf20Sopenharmony_ci return false; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data = pdata->phy_data; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci switch (speed) { 6118c2ecf20Sopenharmony_ci case SPEED_1000: 6128c2ecf20Sopenharmony_ci if (phy_data->speed_set != XGBE_SPEEDSET_1000_10000) 6138c2ecf20Sopenharmony_ci return false; 6148c2ecf20Sopenharmony_ci return true; 6158c2ecf20Sopenharmony_ci case SPEED_2500: 6168c2ecf20Sopenharmony_ci if (phy_data->speed_set != XGBE_SPEEDSET_2500_10000) 6178c2ecf20Sopenharmony_ci return false; 6188c2ecf20Sopenharmony_ci return true; 6198c2ecf20Sopenharmony_ci case SPEED_10000: 6208c2ecf20Sopenharmony_ci return true; 6218c2ecf20Sopenharmony_ci default: 6228c2ecf20Sopenharmony_ci return false; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci unsigned int reg; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci *an_restart = 0; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Link status is latched low, so read once to clear 6338c2ecf20Sopenharmony_ci * and then read again to get current state 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 6368c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return (reg & MDIO_STAT1_LSTATUS) ? 1 : 0; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void xgbe_phy_stop(struct xgbe_prv_data *pdata) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci /* Nothing uniquely required for stop */ 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int xgbe_phy_start(struct xgbe_prv_data *pdata) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci /* Nothing uniquely required for start */ 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic int xgbe_phy_reset(struct xgbe_prv_data *pdata) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci unsigned int reg, count; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* Perform a software reset of the PCS */ 6578c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 6588c2ecf20Sopenharmony_ci reg |= MDIO_CTRL1_RESET; 6598c2ecf20Sopenharmony_ci XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci count = 50; 6628c2ecf20Sopenharmony_ci do { 6638c2ecf20Sopenharmony_ci msleep(20); 6648c2ecf20Sopenharmony_ci reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 6658c2ecf20Sopenharmony_ci } while ((reg & MDIO_CTRL1_RESET) && --count); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (reg & MDIO_CTRL1_RESET) 6688c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void xgbe_phy_exit(struct xgbe_prv_data *pdata) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci /* Nothing uniquely required for exit */ 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int xgbe_phy_init(struct xgbe_prv_data *pdata) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lks = &pdata->phy.lks; 6818c2ecf20Sopenharmony_ci struct xgbe_phy_data *phy_data; 6828c2ecf20Sopenharmony_ci int ret; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci phy_data = devm_kzalloc(pdata->dev, sizeof(*phy_data), GFP_KERNEL); 6858c2ecf20Sopenharmony_ci if (!phy_data) 6868c2ecf20Sopenharmony_ci return -ENOMEM; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Retrieve the PHY speedset */ 6898c2ecf20Sopenharmony_ci ret = device_property_read_u32(pdata->phy_dev, XGBE_SPEEDSET_PROPERTY, 6908c2ecf20Sopenharmony_ci &phy_data->speed_set); 6918c2ecf20Sopenharmony_ci if (ret) { 6928c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 6938c2ecf20Sopenharmony_ci XGBE_SPEEDSET_PROPERTY); 6948c2ecf20Sopenharmony_ci return ret; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci switch (phy_data->speed_set) { 6988c2ecf20Sopenharmony_ci case XGBE_SPEEDSET_1000_10000: 6998c2ecf20Sopenharmony_ci case XGBE_SPEEDSET_2500_10000: 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci default: 7028c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7038c2ecf20Sopenharmony_ci XGBE_SPEEDSET_PROPERTY); 7048c2ecf20Sopenharmony_ci return -EINVAL; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Retrieve the PHY configuration properties */ 7088c2ecf20Sopenharmony_ci if (device_property_present(pdata->phy_dev, XGBE_BLWC_PROPERTY)) { 7098c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(pdata->phy_dev, 7108c2ecf20Sopenharmony_ci XGBE_BLWC_PROPERTY, 7118c2ecf20Sopenharmony_ci phy_data->blwc, 7128c2ecf20Sopenharmony_ci XGBE_SPEEDS); 7138c2ecf20Sopenharmony_ci if (ret) { 7148c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7158c2ecf20Sopenharmony_ci XGBE_BLWC_PROPERTY); 7168c2ecf20Sopenharmony_ci return ret; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci } else { 7198c2ecf20Sopenharmony_ci memcpy(phy_data->blwc, xgbe_phy_blwc, 7208c2ecf20Sopenharmony_ci sizeof(phy_data->blwc)); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (device_property_present(pdata->phy_dev, XGBE_CDR_RATE_PROPERTY)) { 7248c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(pdata->phy_dev, 7258c2ecf20Sopenharmony_ci XGBE_CDR_RATE_PROPERTY, 7268c2ecf20Sopenharmony_ci phy_data->cdr_rate, 7278c2ecf20Sopenharmony_ci XGBE_SPEEDS); 7288c2ecf20Sopenharmony_ci if (ret) { 7298c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7308c2ecf20Sopenharmony_ci XGBE_CDR_RATE_PROPERTY); 7318c2ecf20Sopenharmony_ci return ret; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci } else { 7348c2ecf20Sopenharmony_ci memcpy(phy_data->cdr_rate, xgbe_phy_cdr_rate, 7358c2ecf20Sopenharmony_ci sizeof(phy_data->cdr_rate)); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (device_property_present(pdata->phy_dev, XGBE_PQ_SKEW_PROPERTY)) { 7398c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(pdata->phy_dev, 7408c2ecf20Sopenharmony_ci XGBE_PQ_SKEW_PROPERTY, 7418c2ecf20Sopenharmony_ci phy_data->pq_skew, 7428c2ecf20Sopenharmony_ci XGBE_SPEEDS); 7438c2ecf20Sopenharmony_ci if (ret) { 7448c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7458c2ecf20Sopenharmony_ci XGBE_PQ_SKEW_PROPERTY); 7468c2ecf20Sopenharmony_ci return ret; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci } else { 7498c2ecf20Sopenharmony_ci memcpy(phy_data->pq_skew, xgbe_phy_pq_skew, 7508c2ecf20Sopenharmony_ci sizeof(phy_data->pq_skew)); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (device_property_present(pdata->phy_dev, XGBE_TX_AMP_PROPERTY)) { 7548c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(pdata->phy_dev, 7558c2ecf20Sopenharmony_ci XGBE_TX_AMP_PROPERTY, 7568c2ecf20Sopenharmony_ci phy_data->tx_amp, 7578c2ecf20Sopenharmony_ci XGBE_SPEEDS); 7588c2ecf20Sopenharmony_ci if (ret) { 7598c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7608c2ecf20Sopenharmony_ci XGBE_TX_AMP_PROPERTY); 7618c2ecf20Sopenharmony_ci return ret; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci } else { 7648c2ecf20Sopenharmony_ci memcpy(phy_data->tx_amp, xgbe_phy_tx_amp, 7658c2ecf20Sopenharmony_ci sizeof(phy_data->tx_amp)); 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (device_property_present(pdata->phy_dev, XGBE_DFE_CFG_PROPERTY)) { 7698c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(pdata->phy_dev, 7708c2ecf20Sopenharmony_ci XGBE_DFE_CFG_PROPERTY, 7718c2ecf20Sopenharmony_ci phy_data->dfe_tap_cfg, 7728c2ecf20Sopenharmony_ci XGBE_SPEEDS); 7738c2ecf20Sopenharmony_ci if (ret) { 7748c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7758c2ecf20Sopenharmony_ci XGBE_DFE_CFG_PROPERTY); 7768c2ecf20Sopenharmony_ci return ret; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci } else { 7798c2ecf20Sopenharmony_ci memcpy(phy_data->dfe_tap_cfg, xgbe_phy_dfe_tap_cfg, 7808c2ecf20Sopenharmony_ci sizeof(phy_data->dfe_tap_cfg)); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (device_property_present(pdata->phy_dev, XGBE_DFE_ENA_PROPERTY)) { 7848c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(pdata->phy_dev, 7858c2ecf20Sopenharmony_ci XGBE_DFE_ENA_PROPERTY, 7868c2ecf20Sopenharmony_ci phy_data->dfe_tap_ena, 7878c2ecf20Sopenharmony_ci XGBE_SPEEDS); 7888c2ecf20Sopenharmony_ci if (ret) { 7898c2ecf20Sopenharmony_ci dev_err(pdata->dev, "invalid %s property\n", 7908c2ecf20Sopenharmony_ci XGBE_DFE_ENA_PROPERTY); 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci } else { 7948c2ecf20Sopenharmony_ci memcpy(phy_data->dfe_tap_ena, xgbe_phy_dfe_tap_ena, 7958c2ecf20Sopenharmony_ci sizeof(phy_data->dfe_tap_ena)); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* Initialize supported features */ 7998c2ecf20Sopenharmony_ci XGBE_ZERO_SUP(lks); 8008c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Autoneg); 8018c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Pause); 8028c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Asym_Pause); 8038c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, Backplane); 8048c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseKR_Full); 8058c2ecf20Sopenharmony_ci switch (phy_data->speed_set) { 8068c2ecf20Sopenharmony_ci case XGBE_SPEEDSET_1000_10000: 8078c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 1000baseKX_Full); 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci case XGBE_SPEEDSET_2500_10000: 8108c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 2500baseX_Full); 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) 8158c2ecf20Sopenharmony_ci XGBE_SET_SUP(lks, 10000baseR_FEC); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci pdata->phy_data = phy_data; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_civoid xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci phy_impl->init = xgbe_phy_init; 8278c2ecf20Sopenharmony_ci phy_impl->exit = xgbe_phy_exit; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci phy_impl->reset = xgbe_phy_reset; 8308c2ecf20Sopenharmony_ci phy_impl->start = xgbe_phy_start; 8318c2ecf20Sopenharmony_ci phy_impl->stop = xgbe_phy_stop; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci phy_impl->link_status = xgbe_phy_link_status; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci phy_impl->valid_speed = xgbe_phy_valid_speed; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci phy_impl->use_mode = xgbe_phy_use_mode; 8388c2ecf20Sopenharmony_ci phy_impl->set_mode = xgbe_phy_set_mode; 8398c2ecf20Sopenharmony_ci phy_impl->get_mode = xgbe_phy_get_mode; 8408c2ecf20Sopenharmony_ci phy_impl->switch_mode = xgbe_phy_switch_mode; 8418c2ecf20Sopenharmony_ci phy_impl->cur_mode = xgbe_phy_cur_mode; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci phy_impl->an_mode = xgbe_phy_an_mode; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci phy_impl->an_config = xgbe_phy_an_config; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci phy_impl->an_advertising = xgbe_phy_an_advertising; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci phy_impl->an_outcome = xgbe_phy_an_outcome; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; 8528c2ecf20Sopenharmony_ci phy_impl->kr_training_post = xgbe_phy_kr_training_post; 8538c2ecf20Sopenharmony_ci} 854