[PATCH net-next v4 2/2] net: phy: broadcom: add 1000Base-X support for BCM54616S
Tao Ren
taoren at fb.com
Wed Aug 7 10:00:57 AEST 2019
On 8/6/19 3:00 PM, Heiner Kallweit wrote:
> On 06.08.2019 23:09, Tao Ren wrote:
>> The BCM54616S PHY cannot work properly in RGMII->1000Base-KX mode (for
>> example, on Facebook CMM BMC platform), mainly because genphy functions
>> are designed for copper links, and 1000Base-X (clause 37) auto negotiation
>> needs to be handled differently.
>>
>> This patch enables 1000Base-X support for BCM54616S by customizing 3
>> driver callbacks:
>>
>> - probe: probe callback detects PHY's operation mode based on
>> INTERF_SEL[1:0] pins and 1000X/100FX selection bit in SerDES 100-FX
>> Control register.
>>
>> - config_aneg: bcm54616s_config_aneg_1000bx function is added for auto
>> negotiation in 1000Base-X mode.
>>
>> - read_status: BCM54616S and BCM5482 PHY share the same read_status
>> callback which manually set link speed and duplex mode in 1000Base-X
>> mode.
>>
>> Signed-off-by: Tao Ren <taoren at fb.com>
>> ---
>> Changes in v4:
>> - add bcm54616s_config_aneg_1000bx() to deal with auto negotiation in
>> 1000Base-X mode.
>> Changes in v3:
>> - rename bcm5482_read_status to bcm54xx_read_status so the callback can
>> be shared by BCM5482 and BCM54616S.
>> Changes in v2:
>> - Auto-detect PHY operation mode instead of passing DT node.
>> - move PHY mode auto-detect logic from config_init to probe callback.
>> - only set speed (not including duplex) in read_status callback.
>> - update patch description with more background to avoid confusion.
>> - patch #1 in the series ("net: phy: broadcom: set features explicitly
>> for BCM54616") is dropped: the fix should go to get_features callback
>> which may potentially depend on this patch.
>>
>> drivers/net/phy/broadcom.c | 62 ++++++++++++++++++++++++++++++++++----
>> include/linux/brcmphy.h | 10 ++++--
>> 2 files changed, 64 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
>> index 937d0059e8ac..bf61ed8451e5 100644
>> --- a/drivers/net/phy/broadcom.c
>> +++ b/drivers/net/phy/broadcom.c
>> @@ -383,9 +383,9 @@ static int bcm5482_config_init(struct phy_device *phydev)
>> /*
>> * Select 1000BASE-X register set (primary SerDes)
>> */
>> - reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
>> - bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
>> - reg | BCM5482_SHD_MODE_1000BX);
>> + reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
>> + bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE,
>> + reg | BCM54XX_SHD_MODE_1000BX);
>>
>> /*
>> * LED1=ACTIVITYLED, LED3=LINKSPD[2]
>> @@ -409,7 +409,7 @@ static int bcm5482_config_init(struct phy_device *phydev)
>> return err;
>> }
>>
>> -static int bcm5482_read_status(struct phy_device *phydev)
>> +static int bcm54xx_read_status(struct phy_device *phydev)
>> {
>> int err;
>>
>> @@ -451,12 +451,60 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
>> return ret;
>> }
>>
>> +static int bcm54616s_probe(struct phy_device *phydev)
>> +{
>> + int val, intf_sel;
>> +
>> + val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
>> + if (val < 0)
>> + return val;
>> +
>> + /* The PHY is strapped in RGMII to fiber mode when INTERF_SEL[1:0]
>> + * is 01b.
>> + */
>> + intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1;
>> + if (intf_sel == 1) {
>> + val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
>> + if (val < 0)
>> + return val;
>> +
>> + /* Bit 0 of the SerDes 100-FX Control register, when set
>> + * to 1, sets the MII/RGMII -> 100BASE-FX configuration.
>> + * When this bit is set to 0, it sets the GMII/RGMII ->
>> + * 1000BASE-X configuration.
>> + */
>> + if (!(val & BCM54616S_100FX_MODE))
>> + phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int bcm54616s_config_aneg_1000bx(struct phy_device *phydev)
>> +{
>> + int err;
>> + int adv = 0;
>> +
>> + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
>> + phydev->supported))
>> + adv |= ADVERTISE_1000XFULL;
>> +
>> + err = phy_modify_changed(phydev, MII_ADVERTISE, 0, adv);
>
> The "0" parameter is wrong, it must be ADVERTISE_1000XFULL.
> First you reset the bit, and then you set it or not.
Got it. Will fix it in patch v5. Thanks.
>> + if (err > 0)
>> + err = genphy_restart_aneg(phydev);
>> +
>> + return err;
>> +}
>> +
>> static int bcm54616s_config_aneg(struct phy_device *phydev)
>> {
>> int ret;
>>
>> /* Aneg firsly. */
>> - ret = genphy_config_aneg(phydev);
>> + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX)
>> + ret = bcm54616s_config_aneg_1000bx(phydev);
>> + else
>> + ret = genphy_config_aneg(phydev);
>>
>> /* Then we can set up the delay. */
>> bcm54xx_config_clock_delay(phydev);
>> @@ -655,6 +703,8 @@ static struct phy_driver broadcom_drivers[] = {
>> .config_aneg = bcm54616s_config_aneg,
>> .ack_interrupt = bcm_phy_ack_intr,
>> .config_intr = bcm_phy_config_intr,
>> + .read_status = bcm54xx_read_status,
>
> If you use aneg, you should also read what was negotiated.
> But this function reads neither negotiated duplex mode nor
> pause settings.
Let me see how to fix it.. Will come back soon..
Thanks,
Tao
More information about the openbmc
mailing list