diff options
author | Arun Parameswaran <arunp@broadcom.com> | 2015-10-06 12:25:49 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-08 04:45:52 -0700 |
commit | 8e185d6997bb67068f0ca8f062a50caa2608cf1b (patch) | |
tree | b2d42099f3777dc770023566cfd8d1dc3f1cc761 /drivers/net/phy | |
parent | a1cba5613edf50c2a213fa90c30aa10500b241b7 (diff) |
net: phy: Broadcom Cygnus internal Etherent PHY driver
Add support for the Broadcom Cygnus SoCs internal PHY's.
The PHYs are 1000M/100M/10M capable with support for 'EEE'
and 'APD' (Auto Power Down).
This driver supports the following Broadcom Cygnus SoCs:
- BCM583XX (BCM58300, BCM58302, BCM58303, BCM58305)
- BCM113XX (BCM11300, BCM11320, BCM11350, BCM11360)
The PHY's on these SoC's require some workarounds for
stable operation, both during configuration time and
during suspend/resume. This driver handles the
application of the workarounds.
Signed-off-by: Arun Parameswaran <arunp@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 13 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/bcm-cygnus.c | 158 |
3 files changed, 172 insertions, 0 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 606fdc924768..9d097ae54fb2 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -79,6 +79,19 @@ config BROADCOM_PHY Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, BCM5481 and BCM5482 PHYs. +config BCM_CYGNUS_PHY + tristate "Drivers for Broadcom Cygnus SoC internal PHY" + depends on ARCH_BCM_CYGNUS || COMPILE_TEST + depends on MDIO_BCM_IPROC + select BCM_NET_PHYLIB + ---help--- + This PHY driver is for the 1G internal PHYs of the Broadcom + Cygnus Family SoC. + + Currently supports internal PHY's used in the BCM11300, + BCM11320, BCM11350, BCM11360, BCM58300, BCM58302, + BCM58303 & BCM58305 Broadcom Cygnus SoCs. + config BCM63XX_PHY tristate "Drivers for Broadcom 63xx SOCs internal PHY" depends on BCM63XX diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 6932475a1a8a..7655d47ad8d8 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o +obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c new file mode 100644 index 000000000000..49bbc6826883 --- /dev/null +++ b/drivers/net/phy/bcm-cygnus.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2015 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Broadcom Cygnus SoC internal transceivers support. */ +#include "bcm-phy-lib.h" +#include <linux/brcmphy.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/phy.h> + +/* Broadcom Cygnus Phy specific registers */ +#define MII_BCM_CYGNUS_AFE_VDAC_ICTRL_0 0x91E5 /* VDAL Control register */ + +static int bcm_cygnus_afe_config(struct phy_device *phydev) +{ + int rc; + + /* ensure smdspclk is enabled */ + rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 0x0c30); + if (rc < 0) + return rc; + + /* AFE_VDAC_ICTRL_0 bit 7:4 Iq=1100 for 1g 10bt, normal modes */ + rc = bcm_phy_write_misc(phydev, 0x39, 0x01, 0xA7C8); + if (rc < 0) + return rc; + + /* AFE_HPF_TRIM_OTHERS bit11=1, short cascode enable for all modes*/ + rc = bcm_phy_write_misc(phydev, 0x3A, 0x00, 0x0803); + if (rc < 0) + return rc; + + /* AFE_TX_CONFIG_1 bit 7:4 Iq=1100 for test modes */ + rc = bcm_phy_write_misc(phydev, 0x3A, 0x01, 0xA740); + if (rc < 0) + return rc; + + /* AFE TEMPSEN_OTHERS rcal_HT, rcal_LT 10000 */ + rc = bcm_phy_write_misc(phydev, 0x3A, 0x03, 0x8400); + if (rc < 0) + return rc; + + /* AFE_FUTURE_RSV bit 2:0 rccal <2:0>=100 */ + rc = bcm_phy_write_misc(phydev, 0x3B, 0x00, 0x0004); + if (rc < 0) + return rc; + + /* Adjust bias current trim to overcome digital offSet */ + rc = phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x02); + if (rc < 0) + return rc; + + /* make rcal=100, since rdb default is 000 */ + rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10); + if (rc < 0) + return rc; + + /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ + rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10); + if (rc < 0) + return rc; + + /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ + rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00); + + return 0; +} + +static int bcm_cygnus_config_init(struct phy_device *phydev) +{ + int reg, rc; + + reg = phy_read(phydev, MII_BCM54XX_ECR); + if (reg < 0) + return reg; + + /* Mask interrupts globally. */ + reg |= MII_BCM54XX_ECR_IM; + rc = phy_write(phydev, MII_BCM54XX_ECR, reg); + if (rc) + return rc; + + /* Unmask events of interest */ + reg = ~(MII_BCM54XX_INT_DUPLEX | + MII_BCM54XX_INT_SPEED | + MII_BCM54XX_INT_LINK); + rc = phy_write(phydev, MII_BCM54XX_IMR, reg); + if (rc) + return rc; + + /* Apply AFE settings for the PHY */ + rc = bcm_cygnus_afe_config(phydev); + if (rc) + return rc; + + /* Advertise EEE */ + rc = bcm_phy_enable_eee(phydev); + if (rc) + return rc; + + /* Enable APD */ + return bcm_phy_enable_apd(phydev, false); +} + +static int bcm_cygnus_resume(struct phy_device *phydev) +{ + int rc; + + genphy_resume(phydev); + + /* Re-initialize the PHY to apply AFE work-arounds and + * configurations when coming out of suspend. + */ + rc = bcm_cygnus_config_init(phydev); + if (rc) + return rc; + + /* restart auto negotiation with the new settings */ + return genphy_config_aneg(phydev); +} + +static struct phy_driver bcm_cygnus_phy_driver[] = { +{ + .phy_id = PHY_ID_BCM_CYGNUS, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom Cygnus PHY", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .config_init = bcm_cygnus_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm_phy_ack_intr, + .config_intr = bcm_phy_config_intr, + .suspend = genphy_suspend, + .resume = bcm_cygnus_resume, +} }; + +static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = { + { PHY_ID_BCM_CYGNUS, 0xfffffff0, }, + { } +}; +MODULE_DEVICE_TABLE(mdio, bcm_cygnus_phy_tbl); + +module_phy_driver(bcm_cygnus_phy_driver); + +MODULE_DESCRIPTION("Broadcom Cygnus internal PHY driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Broadcom Corporation"); |