Skip to content

Commit

Permalink
net: phy: Add Broadcom phy library for common interfaces
Browse files Browse the repository at this point in the history
This patch adds the Broadcom phy library to consolidate common
interfaces shared by Broadcom phy's.

Moved the common interfaces to the 'bcm-phy-lib.c' and updated
the Broadcom PHY drivers to use the new APIs.

Signed-off-by: Arun Parameswaran <arunp@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Arun Parameswaran authored and davem330 committed Oct 8, 2015
1 parent ddc24ae commit a1cba56
Show file tree
Hide file tree
Showing 8 changed files with 332 additions and 256 deletions.
6 changes: 6 additions & 0 deletions drivers/net/phy/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,26 @@ config SMSC_PHY
---help---
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs

config BCM_NET_PHYLIB
tristate

config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"
select BCM_NET_PHYLIB
---help---
Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
BCM5481 and BCM5482 PHYs.

config BCM63XX_PHY
tristate "Drivers for Broadcom 63xx SOCs internal PHY"
depends on BCM63XX
select BCM_NET_PHYLIB
---help---
Currently supports the 6348 and 6358 PHYs.

config BCM7XXX_PHY
tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
select BCM_NET_PHYLIB
---help---
Currently supports the BCM7366, BCM7439, BCM7445, and
40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
Expand Down
1 change: 1 addition & 0 deletions drivers/net/phy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_TERANETICS_PHY) += teranetics.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
Expand Down
208 changes: 208 additions & 0 deletions drivers/net/phy/bcm-phy-lib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* 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.
*/

#include "bcm-phy-lib.h"
#include <linux/brcmphy.h>
#include <linux/export.h>
#include <linux/mdio.h>
#include <linux/phy.h>

#define MII_BCM_CHANNEL_WIDTH 0x2000
#define BCM_CL45VEN_EEE_ADV 0x3c

int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
{
int rc;

rc = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
if (rc < 0)
return rc;

return phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
}
EXPORT_SYMBOL_GPL(bcm_phy_write_exp);

int bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
{
int val;

val = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
if (val < 0)
return val;

val = phy_read(phydev, MII_BCM54XX_EXP_DATA);

/* Restore default value. It's O.K. if this write fails. */
phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);

return val;
}
EXPORT_SYMBOL_GPL(bcm_phy_read_exp);

int bcm_phy_write_misc(struct phy_device *phydev,
u16 reg, u16 chl, u16 val)
{
int rc;
int tmp;

rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
if (rc < 0)
return rc;

tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
if (rc < 0)
return rc;

tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
rc = bcm_phy_write_exp(phydev, tmp, val);

return rc;
}
EXPORT_SYMBOL_GPL(bcm_phy_write_misc);

int bcm_phy_read_misc(struct phy_device *phydev,
u16 reg, u16 chl)
{
int rc;
int tmp;

rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
if (rc < 0)
return rc;

tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
if (rc < 0)
return rc;

tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
rc = bcm_phy_read_exp(phydev, tmp);

return rc;
}
EXPORT_SYMBOL_GPL(bcm_phy_read_misc);

int bcm_phy_ack_intr(struct phy_device *phydev)
{
int reg;

/* Clear pending interrupts. */
reg = phy_read(phydev, MII_BCM54XX_ISR);
if (reg < 0)
return reg;

return 0;
}
EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);

int bcm_phy_config_intr(struct phy_device *phydev)
{
int reg;

reg = phy_read(phydev, MII_BCM54XX_ECR);
if (reg < 0)
return reg;

if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
reg &= ~MII_BCM54XX_ECR_IM;
else
reg |= MII_BCM54XX_ECR_IM;

return phy_write(phydev, MII_BCM54XX_ECR, reg);
}
EXPORT_SYMBOL_GPL(bcm_phy_config_intr);

int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
{
phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
}
EXPORT_SYMBOL_GPL(bcm_phy_read_shadow);

int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
u16 val)
{
return phy_write(phydev, MII_BCM54XX_SHD,
MII_BCM54XX_SHD_WRITE |
MII_BCM54XX_SHD_VAL(shadow) |
MII_BCM54XX_SHD_DATA(val));
}
EXPORT_SYMBOL_GPL(bcm_phy_write_shadow);

int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down)
{
int val;

if (dll_pwr_down) {
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
if (val < 0)
return val;

val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
}

val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
if (val < 0)
return val;

/* Clear APD bits */
val &= BCM_APD_CLR_MASK;

if (phydev->autoneg == AUTONEG_ENABLE)
val |= BCM54XX_SHD_APD_EN;
else
val |= BCM_NO_ANEG_APD_EN;

/* Enable energy detect single link pulse for easy wakeup */
val |= BCM_APD_SINGLELP_EN;

/* Enable Auto Power-Down (APD) for the PHY */
return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
}
EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);

int bcm_phy_enable_eee(struct phy_device *phydev)
{
int val;

/* Enable EEE at PHY level */
val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
MDIO_MMD_AN, phydev->addr);
if (val < 0)
return val;

val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;

phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
MDIO_MMD_AN, phydev->addr, (u32)val);

/* Advertise EEE */
val = phy_read_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
MDIO_MMD_AN, phydev->addr);
if (val < 0)
return val;

val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);

phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
MDIO_MMD_AN, phydev->addr, (u32)val);

return 0;
}
EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
37 changes: 37 additions & 0 deletions drivers/net/phy/bcm-phy-lib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.
*/

#ifndef _LINUX_BCM_PHY_LIB_H
#define _LINUX_BCM_PHY_LIB_H

#include <linux/phy.h>

int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);

int bcm_phy_write_misc(struct phy_device *phydev,
u16 reg, u16 chl, u16 value);
int bcm_phy_read_misc(struct phy_device *phydev,
u16 reg, u16 chl);

int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
u16 val);
int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow);

int bcm_phy_ack_intr(struct phy_device *phydev);
int bcm_phy_config_intr(struct phy_device *phydev);

int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);

int bcm_phy_enable_eee(struct phy_device *phydev);
#endif /* _LINUX_BCM_PHY_LIB_H */
38 changes: 5 additions & 33 deletions drivers/net/phy/bcm63xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include "bcm-phy-lib.h"
#include <linux/module.h>
#include <linux/phy.h>

Expand Down Expand Up @@ -42,35 +43,6 @@ static int bcm63xx_config_init(struct phy_device *phydev)
return phy_write(phydev, MII_BCM63XX_IR, reg);
}

static int bcm63xx_ack_interrupt(struct phy_device *phydev)
{
int reg;

/* Clear pending interrupts. */
reg = phy_read(phydev, MII_BCM63XX_IR);
if (reg < 0)
return reg;

return 0;
}

static int bcm63xx_config_intr(struct phy_device *phydev)
{
int reg, err;

reg = phy_read(phydev, MII_BCM63XX_IR);
if (reg < 0)
return reg;

if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
reg &= ~MII_BCM63XX_IR_GMASK;
else
reg |= MII_BCM63XX_IR_GMASK;

err = phy_write(phydev, MII_BCM63XX_IR, reg);
return err;
}

static struct phy_driver bcm63xx_driver[] = {
{
.phy_id = 0x00406000,
Expand All @@ -82,8 +54,8 @@ static struct phy_driver bcm63xx_driver[] = {
.config_init = bcm63xx_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = bcm63xx_ack_interrupt,
.config_intr = bcm63xx_config_intr,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
.driver = { .owner = THIS_MODULE },
}, {
/* same phy as above, with just a different OUI */
Expand All @@ -95,8 +67,8 @@ static struct phy_driver bcm63xx_driver[] = {
.config_init = bcm63xx_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = bcm63xx_ack_interrupt,
.config_intr = bcm63xx_config_intr,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
.driver = { .owner = THIS_MODULE },
} };

Expand Down
Loading

0 comments on commit a1cba56

Please sign in to comment.