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