11bd4fe43Sopenharmony_ci/* 21bd4fe43Sopenharmony_ci * Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED. 31bd4fe43Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 41bd4fe43Sopenharmony_ci * you may not use this file except in compliance with the License. 51bd4fe43Sopenharmony_ci * You may obtain a copy of the License at 61bd4fe43Sopenharmony_ci * 71bd4fe43Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 81bd4fe43Sopenharmony_ci * 91bd4fe43Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 101bd4fe43Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 111bd4fe43Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 121bd4fe43Sopenharmony_ci * See the License for the specific language governing permissions and 131bd4fe43Sopenharmony_ci * limitations under the License. 141bd4fe43Sopenharmony_ci */ 151bd4fe43Sopenharmony_ci 161bd4fe43Sopenharmony_ci#include "eth_phy.h" 171bd4fe43Sopenharmony_ci#include "linux/kernel.h" 181bd4fe43Sopenharmony_ci#include "hieth.h" 191bd4fe43Sopenharmony_ci#include "mdio.h" 201bd4fe43Sopenharmony_ci#include "stdio.h" 211bd4fe43Sopenharmony_ci 221bd4fe43Sopenharmony_ci#define WAIT_PHY_AUTO_NEG_TIMES 25 231bd4fe43Sopenharmony_ci 241bd4fe43Sopenharmony_cibool HiethGetPhyStat(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess, uint32_t *state) 251bd4fe43Sopenharmony_ci{ 261bd4fe43Sopenharmony_ci int32_t phyState; 271bd4fe43Sopenharmony_ci int32_t i; 281bd4fe43Sopenharmony_ci 291bd4fe43Sopenharmony_ci *state = 0; 301bd4fe43Sopenharmony_ci phyState = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR); 311bd4fe43Sopenharmony_ci if (phyState < 0) { 321bd4fe43Sopenharmony_ci return false; 331bd4fe43Sopenharmony_ci } 341bd4fe43Sopenharmony_ci if (!((uint32_t)phyState & BMSR_AN_COMPLETE)) { 351bd4fe43Sopenharmony_ci HDF_LOGE("waiting for auto-negotiation completed!"); 361bd4fe43Sopenharmony_ci for (i = 0; i < WAIT_PHY_AUTO_NEG_TIMES; i++) { 371bd4fe43Sopenharmony_ci phyState = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR); 381bd4fe43Sopenharmony_ci if ((phyState >= 0) && ((uint32_t)phyState & BMSR_AN_COMPLETE)) { 391bd4fe43Sopenharmony_ci break; 401bd4fe43Sopenharmony_ci } 411bd4fe43Sopenharmony_ci msleep(10); 421bd4fe43Sopenharmony_ci } 431bd4fe43Sopenharmony_ci } 441bd4fe43Sopenharmony_ci if ((uint32_t)phyState & BMSR_AN_COMPLETE) { 451bd4fe43Sopenharmony_ci if ((uint32_t)phyState & BMSR_LINK) { 461bd4fe43Sopenharmony_ci *state |= ETH_PHY_STAT_LINK; 471bd4fe43Sopenharmony_ci } 481bd4fe43Sopenharmony_ci return true; 491bd4fe43Sopenharmony_ci } 501bd4fe43Sopenharmony_ci return false; 511bd4fe43Sopenharmony_ci} 521bd4fe43Sopenharmony_ci 531bd4fe43Sopenharmony_ciint32_t MiiphyLink(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess) 541bd4fe43Sopenharmony_ci{ 551bd4fe43Sopenharmony_ci int32_t reg; 561bd4fe43Sopenharmony_ci 571bd4fe43Sopenharmony_ci reg = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR); 581bd4fe43Sopenharmony_ci if (reg < 0) { 591bd4fe43Sopenharmony_ci HDF_LOGE("PHY_BMSR read failed, assuming no link"); 601bd4fe43Sopenharmony_ci return HDF_SUCCESS; 611bd4fe43Sopenharmony_ci } 621bd4fe43Sopenharmony_ci 631bd4fe43Sopenharmony_ci /* Determine if a link is active */ 641bd4fe43Sopenharmony_ci if (((uint32_t)reg & BMSR_LINK) != 0) { 651bd4fe43Sopenharmony_ci return HDF_FAILURE; 661bd4fe43Sopenharmony_ci } else { 671bd4fe43Sopenharmony_ci return HDF_SUCCESS; 681bd4fe43Sopenharmony_ci } 691bd4fe43Sopenharmony_ci} 701bd4fe43Sopenharmony_ci 711bd4fe43Sopenharmony_ci/***************************************************************************** 721bd4fe43Sopenharmony_ci * 731bd4fe43Sopenharmony_ci * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/ 741bd4fe43Sopenharmony_ci * 1000BASE-T, or on error. 751bd4fe43Sopenharmony_ci */ 761bd4fe43Sopenharmony_cistatic int32_t MiiphyIs1000baseX(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess) 771bd4fe43Sopenharmony_ci{ 781bd4fe43Sopenharmony_ci int32_t reg; 791bd4fe43Sopenharmony_ci 801bd4fe43Sopenharmony_ci reg = HiethMdioRead(ld, phyAccess->phyAddr, PHY_EXSR); 811bd4fe43Sopenharmony_ci if (reg < 0) { 821bd4fe43Sopenharmony_ci HDF_LOGE("PHY_EXSR read failed, assume no 1000BASE-X"); 831bd4fe43Sopenharmony_ci return HDF_SUCCESS; 841bd4fe43Sopenharmony_ci } 851bd4fe43Sopenharmony_ci return ((uint32_t)reg & (EXSR_1000XF | EXSR_1000XH)) != 0; 861bd4fe43Sopenharmony_ci} 871bd4fe43Sopenharmony_ci 881bd4fe43Sopenharmony_ci/***************************************************************************** 891bd4fe43Sopenharmony_ci * 901bd4fe43Sopenharmony_ci * Determine the ethernet speed (10/100/1000). Return 10 on error. 911bd4fe43Sopenharmony_ci */ 921bd4fe43Sopenharmony_ciint32_t MiiphySpeed(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess) 931bd4fe43Sopenharmony_ci{ 941bd4fe43Sopenharmony_ci int32_t bmcr, anlpar; 951bd4fe43Sopenharmony_ci int32_t btsr, val; 961bd4fe43Sopenharmony_ci 971bd4fe43Sopenharmony_ci val = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR); 981bd4fe43Sopenharmony_ci if (val < 0) { 991bd4fe43Sopenharmony_ci HDF_LOGE("PHY 1000BT status[read PHY_BMSR]\n"); 1001bd4fe43Sopenharmony_ci return PHY_SPEED_10; 1011bd4fe43Sopenharmony_ci } 1021bd4fe43Sopenharmony_ci 1031bd4fe43Sopenharmony_ci if ((uint32_t)val & BMSR_ESTATEN) { 1041bd4fe43Sopenharmony_ci if (MiiphyIs1000baseX(ld, phyAccess)) { 1051bd4fe43Sopenharmony_ci return PHY_SPEED_1000; 1061bd4fe43Sopenharmony_ci } 1071bd4fe43Sopenharmony_ci btsr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_1000BTSR); 1081bd4fe43Sopenharmony_ci if (btsr < 0) { 1091bd4fe43Sopenharmony_ci HDF_LOGE("PHY 1000BT status[read PHY_1000BTSR]\n"); 1101bd4fe43Sopenharmony_ci return PHY_SPEED_10; 1111bd4fe43Sopenharmony_ci } 1121bd4fe43Sopenharmony_ci if (btsr != 0xFFFF && ((uint32_t)btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) { 1131bd4fe43Sopenharmony_ci return PHY_SPEED_1000; 1141bd4fe43Sopenharmony_ci } 1151bd4fe43Sopenharmony_ci } 1161bd4fe43Sopenharmony_ci 1171bd4fe43Sopenharmony_ci /* Check Basic Management Control Register first. */ 1181bd4fe43Sopenharmony_ci bmcr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMCR); 1191bd4fe43Sopenharmony_ci if (bmcr < 0) { 1201bd4fe43Sopenharmony_ci HDF_LOGE("PHY speed read failed[read PHY_BMCR]"); 1211bd4fe43Sopenharmony_ci return PHY_SPEED_10; 1221bd4fe43Sopenharmony_ci } 1231bd4fe43Sopenharmony_ci 1241bd4fe43Sopenharmony_ci if ((uint32_t)bmcr & BMCR_AN_ENABLE) { 1251bd4fe43Sopenharmony_ci anlpar = HiethMdioRead(ld, phyAccess->phyAddr, PHY_ANLPAR); 1261bd4fe43Sopenharmony_ci if (anlpar < 0) { 1271bd4fe43Sopenharmony_ci HDF_LOGE("PHY AN speed failed[anlpar]"); 1281bd4fe43Sopenharmony_ci return PHY_SPEED_10; 1291bd4fe43Sopenharmony_ci } 1301bd4fe43Sopenharmony_ci return ((uint32_t)anlpar & ANLPAR_100) ? PHY_SPEED_100 : PHY_SPEED_10; 1311bd4fe43Sopenharmony_ci } 1321bd4fe43Sopenharmony_ci return ((uint32_t)bmcr & BMCR_SPEED100) ? PHY_SPEED_100 : PHY_SPEED_10; 1331bd4fe43Sopenharmony_ci} 1341bd4fe43Sopenharmony_ci 1351bd4fe43Sopenharmony_ci/* 1361bd4fe43Sopenharmony_ci * Determine full/half duplex. Return half on error. 1371bd4fe43Sopenharmony_ci */ 1381bd4fe43Sopenharmony_ciint32_t MiiphyDuplex(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess) 1391bd4fe43Sopenharmony_ci{ 1401bd4fe43Sopenharmony_ci int32_t bmcr, anlpar, val; 1411bd4fe43Sopenharmony_ci val = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR); 1421bd4fe43Sopenharmony_ci if (val < 0) { 1431bd4fe43Sopenharmony_ci HDF_LOGE("PHY duplex read failed"); 1441bd4fe43Sopenharmony_ci return PHY_DUPLEX_HALF; 1451bd4fe43Sopenharmony_ci } 1461bd4fe43Sopenharmony_ci 1471bd4fe43Sopenharmony_ci if ((uint32_t)val & BMSR_ESTATEN) { 1481bd4fe43Sopenharmony_ci int32_t btsr; 1491bd4fe43Sopenharmony_ci /* Check for 1000BASE-X */ 1501bd4fe43Sopenharmony_ci if (MiiphyIs1000baseX(ld, phyAccess)) { 1511bd4fe43Sopenharmony_ci /* 1000BASE-X */ 1521bd4fe43Sopenharmony_ci anlpar = HiethMdioRead(ld, phyAccess->phyAddr, PHY_ANLPAR); 1531bd4fe43Sopenharmony_ci if (anlpar < 0) { 1541bd4fe43Sopenharmony_ci HDF_LOGE("1000BASE-X PHY AN duplex failed"); 1551bd4fe43Sopenharmony_ci return PHY_DUPLEX_HALF; 1561bd4fe43Sopenharmony_ci } 1571bd4fe43Sopenharmony_ci } 1581bd4fe43Sopenharmony_ci /* No 1000BASE-X, so assume 1000BASE-T/1000BASE-TX 10BASE-T register set */ 1591bd4fe43Sopenharmony_ci /* Check for 1000BASE-T. */ 1601bd4fe43Sopenharmony_ci btsr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_1000BTSR); 1611bd4fe43Sopenharmony_ci if (btsr < 0) { 1621bd4fe43Sopenharmony_ci HDF_LOGE("PHY 1000BT status"); 1631bd4fe43Sopenharmony_ci return PHY_DUPLEX_HALF; 1641bd4fe43Sopenharmony_ci } 1651bd4fe43Sopenharmony_ci 1661bd4fe43Sopenharmony_ci if (btsr != 0xFFFF) { 1671bd4fe43Sopenharmony_ci if ((uint32_t)btsr & PHY_1000BTSR_1000FD) { 1681bd4fe43Sopenharmony_ci return PHY_DUPLEX_FULL; 1691bd4fe43Sopenharmony_ci } else if ((uint32_t)btsr & PHY_1000BTSR_1000HD) { 1701bd4fe43Sopenharmony_ci return PHY_DUPLEX_HALF; 1711bd4fe43Sopenharmony_ci } 1721bd4fe43Sopenharmony_ci } 1731bd4fe43Sopenharmony_ci } 1741bd4fe43Sopenharmony_ci /* Check Basic Management Control Register first. */ 1751bd4fe43Sopenharmony_ci bmcr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMCR); 1761bd4fe43Sopenharmony_ci if (bmcr < 0) { 1771bd4fe43Sopenharmony_ci HDF_LOGE("PHY duplex"); 1781bd4fe43Sopenharmony_ci return PHY_DUPLEX_HALF; 1791bd4fe43Sopenharmony_ci } 1801bd4fe43Sopenharmony_ci /* Check if auto-negotiation is on. */ 1811bd4fe43Sopenharmony_ci if ((uint32_t)bmcr & BMCR_AN_ENABLE) { 1821bd4fe43Sopenharmony_ci /* Get auto-negotiation results. */ 1831bd4fe43Sopenharmony_ci anlpar = HiethMdioRead(ld, phyAccess->phyAddr, PHY_ANLPAR); 1841bd4fe43Sopenharmony_ci if (anlpar < 0) { 1851bd4fe43Sopenharmony_ci HDF_LOGE("PHY AN duplex"); 1861bd4fe43Sopenharmony_ci return PHY_DUPLEX_HALF; 1871bd4fe43Sopenharmony_ci } 1881bd4fe43Sopenharmony_ci return ((uint32_t)anlpar & (ANLPAR_10FD | ANLPAR_TXFD)) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF; 1891bd4fe43Sopenharmony_ci } 1901bd4fe43Sopenharmony_ci /* Get speed from basic control settings. */ 1911bd4fe43Sopenharmony_ci return ((uint32_t)bmcr & BMCR_FULL_DUPLEX) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF; 1921bd4fe43Sopenharmony_ci} 193