1*a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0 28e185d69SArun Parameswaran /* 38e185d69SArun Parameswaran * Copyright (C) 2015 Broadcom Corporation 48e185d69SArun Parameswaran */ 58e185d69SArun Parameswaran 68e185d69SArun Parameswaran /* Broadcom Cygnus SoC internal transceivers support. */ 78e185d69SArun Parameswaran #include "bcm-phy-lib.h" 88e185d69SArun Parameswaran #include <linux/brcmphy.h> 98e185d69SArun Parameswaran #include <linux/module.h> 108e185d69SArun Parameswaran #include <linux/netdevice.h> 118e185d69SArun Parameswaran #include <linux/phy.h> 128e185d69SArun Parameswaran 138e185d69SArun Parameswaran /* Broadcom Cygnus Phy specific registers */ 148e185d69SArun Parameswaran #define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0 0x91E5 /* VDAL Control register */ 158e185d69SArun Parameswaran 168e185d69SArun Parameswaran static int bcm_cygnus_afe_config(struct phy_device *phydev) 178e185d69SArun Parameswaran { 188e185d69SArun Parameswaran int rc; 198e185d69SArun Parameswaran 208e185d69SArun Parameswaran /* ensure smdspclk is enabled */ 218e185d69SArun Parameswaran rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 0x0c30); 228e185d69SArun Parameswaran if (rc < 0) 238e185d69SArun Parameswaran return rc; 248e185d69SArun Parameswaran 258e185d69SArun Parameswaran /* AFE_VDAC_ICTRL_0 bit 7:4 Iq=1100 for 1g 10bt, normal modes */ 268e185d69SArun Parameswaran rc = bcm_phy_write_misc(phydev, 0x39, 0x01, 0xA7C8); 278e185d69SArun Parameswaran if (rc < 0) 288e185d69SArun Parameswaran return rc; 298e185d69SArun Parameswaran 308e185d69SArun Parameswaran /* AFE_HPF_TRIM_OTHERS bit11=1, short cascode enable for all modes*/ 318e185d69SArun Parameswaran rc = bcm_phy_write_misc(phydev, 0x3A, 0x00, 0x0803); 328e185d69SArun Parameswaran if (rc < 0) 338e185d69SArun Parameswaran return rc; 348e185d69SArun Parameswaran 358e185d69SArun Parameswaran /* AFE_TX_CONFIG_1 bit 7:4 Iq=1100 for test modes */ 368e185d69SArun Parameswaran rc = bcm_phy_write_misc(phydev, 0x3A, 0x01, 0xA740); 378e185d69SArun Parameswaran if (rc < 0) 388e185d69SArun Parameswaran return rc; 398e185d69SArun Parameswaran 408e185d69SArun Parameswaran /* AFE TEMPSEN_OTHERS rcal_HT, rcal_LT 10000 */ 418e185d69SArun Parameswaran rc = bcm_phy_write_misc(phydev, 0x3A, 0x03, 0x8400); 428e185d69SArun Parameswaran if (rc < 0) 438e185d69SArun Parameswaran return rc; 448e185d69SArun Parameswaran 458e185d69SArun Parameswaran /* AFE_FUTURE_RSV bit 2:0 rccal <2:0>=100 */ 468e185d69SArun Parameswaran rc = bcm_phy_write_misc(phydev, 0x3B, 0x00, 0x0004); 478e185d69SArun Parameswaran if (rc < 0) 488e185d69SArun Parameswaran return rc; 498e185d69SArun Parameswaran 508e185d69SArun Parameswaran /* Adjust bias current trim to overcome digital offSet */ 518e185d69SArun Parameswaran rc = phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x02); 528e185d69SArun Parameswaran if (rc < 0) 538e185d69SArun Parameswaran return rc; 548e185d69SArun Parameswaran 558e185d69SArun Parameswaran /* make rcal=100, since rdb default is 000 */ 5679fb218dSFlorian Fainelli rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); 578e185d69SArun Parameswaran if (rc < 0) 588e185d69SArun Parameswaran return rc; 598e185d69SArun Parameswaran 608e185d69SArun Parameswaran /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ 6179fb218dSFlorian Fainelli rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); 628e185d69SArun Parameswaran if (rc < 0) 638e185d69SArun Parameswaran return rc; 648e185d69SArun Parameswaran 658e185d69SArun Parameswaran /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ 6679fb218dSFlorian Fainelli rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); 678e185d69SArun Parameswaran 688e185d69SArun Parameswaran return 0; 698e185d69SArun Parameswaran } 708e185d69SArun Parameswaran 718e185d69SArun Parameswaran static int bcm_cygnus_config_init(struct phy_device *phydev) 728e185d69SArun Parameswaran { 738e185d69SArun Parameswaran int reg, rc; 748e185d69SArun Parameswaran 758e185d69SArun Parameswaran reg = phy_read(phydev, MII_BCM54XX_ECR); 768e185d69SArun Parameswaran if (reg < 0) 778e185d69SArun Parameswaran return reg; 788e185d69SArun Parameswaran 798e185d69SArun Parameswaran /* Mask interrupts globally. */ 808e185d69SArun Parameswaran reg |= MII_BCM54XX_ECR_IM; 818e185d69SArun Parameswaran rc = phy_write(phydev, MII_BCM54XX_ECR, reg); 828e185d69SArun Parameswaran if (rc) 838e185d69SArun Parameswaran return rc; 848e185d69SArun Parameswaran 858e185d69SArun Parameswaran /* Unmask events of interest */ 868e185d69SArun Parameswaran reg = ~(MII_BCM54XX_INT_DUPLEX | 878e185d69SArun Parameswaran MII_BCM54XX_INT_SPEED | 888e185d69SArun Parameswaran MII_BCM54XX_INT_LINK); 898e185d69SArun Parameswaran rc = phy_write(phydev, MII_BCM54XX_IMR, reg); 908e185d69SArun Parameswaran if (rc) 918e185d69SArun Parameswaran return rc; 928e185d69SArun Parameswaran 938e185d69SArun Parameswaran /* Apply AFE settings for the PHY */ 948e185d69SArun Parameswaran rc = bcm_cygnus_afe_config(phydev); 958e185d69SArun Parameswaran if (rc) 968e185d69SArun Parameswaran return rc; 978e185d69SArun Parameswaran 988e185d69SArun Parameswaran /* Advertise EEE */ 9999cec8a4SFlorian Fainelli rc = bcm_phy_set_eee(phydev, true); 1008e185d69SArun Parameswaran if (rc) 1018e185d69SArun Parameswaran return rc; 1028e185d69SArun Parameswaran 1038e185d69SArun Parameswaran /* Enable APD */ 1048e185d69SArun Parameswaran return bcm_phy_enable_apd(phydev, false); 1058e185d69SArun Parameswaran } 1068e185d69SArun Parameswaran 1078e185d69SArun Parameswaran static int bcm_cygnus_resume(struct phy_device *phydev) 1088e185d69SArun Parameswaran { 1098e185d69SArun Parameswaran int rc; 1108e185d69SArun Parameswaran 1118e185d69SArun Parameswaran genphy_resume(phydev); 1128e185d69SArun Parameswaran 1138e185d69SArun Parameswaran /* Re-initialize the PHY to apply AFE work-arounds and 1148e185d69SArun Parameswaran * configurations when coming out of suspend. 1158e185d69SArun Parameswaran */ 1168e185d69SArun Parameswaran rc = bcm_cygnus_config_init(phydev); 1178e185d69SArun Parameswaran if (rc) 1188e185d69SArun Parameswaran return rc; 1198e185d69SArun Parameswaran 1208e185d69SArun Parameswaran /* restart auto negotiation with the new settings */ 1218e185d69SArun Parameswaran return genphy_config_aneg(phydev); 1228e185d69SArun Parameswaran } 1238e185d69SArun Parameswaran 1248e185d69SArun Parameswaran static struct phy_driver bcm_cygnus_phy_driver[] = { 1258e185d69SArun Parameswaran { 1268e185d69SArun Parameswaran .phy_id = PHY_ID_BCM_CYGNUS, 1278e185d69SArun Parameswaran .phy_id_mask = 0xfffffff0, 1288e185d69SArun Parameswaran .name = "Broadcom Cygnus PHY", 129529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 1308e185d69SArun Parameswaran .config_init = bcm_cygnus_config_init, 1318e185d69SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 1328e185d69SArun Parameswaran .config_intr = bcm_phy_config_intr, 1338e185d69SArun Parameswaran .suspend = genphy_suspend, 1348e185d69SArun Parameswaran .resume = bcm_cygnus_resume, 1358e185d69SArun Parameswaran } }; 1368e185d69SArun Parameswaran 1378e185d69SArun Parameswaran static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = { 1388e185d69SArun Parameswaran { PHY_ID_BCM_CYGNUS, 0xfffffff0, }, 1398e185d69SArun Parameswaran { } 1408e185d69SArun Parameswaran }; 1418e185d69SArun Parameswaran MODULE_DEVICE_TABLE(mdio, bcm_cygnus_phy_tbl); 1428e185d69SArun Parameswaran 1438e185d69SArun Parameswaran module_phy_driver(bcm_cygnus_phy_driver); 1448e185d69SArun Parameswaran 1458e185d69SArun Parameswaran MODULE_DESCRIPTION("Broadcom Cygnus internal PHY driver"); 1468e185d69SArun Parameswaran MODULE_LICENSE("GPL v2"); 1478e185d69SArun Parameswaran MODULE_AUTHOR("Broadcom Corporation"); 148