xref: /linux/drivers/net/phy/bcm-cygnus.c (revision 99cec8a4dda28972067c274a4215422262dc5522)
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