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