diff mbox series

[4/7] net: stmmac: introducing support for DWC xPCS logics

Message ID 1556126241-2774-5-git-send-email-weifeng.voon@intel.com
State Changes Requested
Delegated to: David Miller
Headers show
Series net: stmmac: enable EHL SGMII | expand

Commit Message

Voon, Weifeng April 24, 2019, 5:17 p.m. UTC
From: Ong Boon Leong <boon.leong.ong@intel.com>

xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
into a GbE controller that uses DWC EQoS MAC controller. An example of
HW configuration is shown below:-

  <-----------------GBE Controller---------->|<--External PHY chip-->

  +----------+         +----+    +---+               +--------------+
  |   EQoS   | <-GMII->|xPCS|<-->|L1 | <-- SGMII --> | External GbE |
  |   MAC    |         |    |    |PHY|               | PHY Chip     |
  +----------+         +----+    +---+               +--------------+
         ^               ^                                  ^
         |               |                                  |
         +---------------------MDIO-------------------------+

xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
differentiate it from external PHY chip that is discovered over MDIO.
Therefore, xpcs_phy_addr is introduced in stmmac platform data
(plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
belongs to external PHY.

Basic functionalities for initializing xPCS and configuring auto
negotiation (AN), loopback, link status, AN advertisement and Link
Partner ability are implemented.

xPCS interrupt handling for C37 AN complete is also implemented.

Tested-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@intel.com>
Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
Reviewed-by: Baoli Zhang <baoli.zhang@intel.com>
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h | 288 ++++++++++++++++++++++++++
 drivers/net/ethernet/stmicro/stmmac/hwif.h    |  17 ++
 include/linux/stmmac.h                        |   1 +
 3 files changed, 306 insertions(+)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h

Comments

Andrew Lunn April 24, 2019, 1:41 p.m. UTC | #1
On Thu, Apr 25, 2019 at 01:17:18AM +0800, Weifeng Voon wrote:
> From: Ong Boon Leong <boon.leong.ong@intel.com>
> 
> xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
> into a GbE controller that uses DWC EQoS MAC controller. An example of
> HW configuration is shown below:-
> 
>   <-----------------GBE Controller---------->|<--External PHY chip-->
> 
>   +----------+         +----+    +---+               +--------------+
>   |   EQoS   | <-GMII->|xPCS|<-->|L1 | <-- SGMII --> | External GbE |
>   |   MAC    |         |    |    |PHY|               | PHY Chip     |
>   +----------+         +----+    +---+               +--------------+
>          ^               ^                                  ^
>          |               |                                  |
>          +---------------------MDIO-------------------------+
> 
> xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
> differentiate it from external PHY chip that is discovered over MDIO.
> Therefore, xpcs_phy_addr is introduced in stmmac platform data
> (plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
> belongs to external PHY.
> 
> Basic functionalities for initializing xPCS and configuring auto
> negotiation (AN), loopback, link status, AN advertisement and Link
> Partner ability are implemented.
> 
> xPCS interrupt handling for C37 AN complete is also implemented.
> 
> Tested-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
> Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@intel.com>
> Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
> Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
> Reviewed-by: Baoli Zhang <baoli.zhang@intel.com>
> Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>

You need your own signed-off-by here, since you are submitting it.

> ---
>  drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h | 288 ++++++++++++++++++++++++++
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  17 ++
>  include/linux/stmmac.h                        |   1 +
>  3 files changed, 306 insertions(+)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> new file mode 100644
> index 0000000..446b714
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> @@ -0,0 +1,288 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* dw_xpcs.h: DWC Ethernet Physical Coding Sublayer Header
> + *
> + * Copyright (c) 2019, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + */

Since you have a SPDX line, you don't need the license boilerplate.

> +#ifndef __DW_XPCS_H__
> +#define __DW_XPCS_H__
> +
> +#include <linux/mdio.h>
> +#include <linux/bitops.h>
> +#include "stmmac.h"
> +
> +/* XPCS Control & MII MMD Device Addresses */
> +#define XPCS_MDIO_CONTROL_MMD	MDIO_MMD_VEND1
> +#define XPCS_MDIO_MII_MMD	MDIO_MMD_VEND2
> +
> +/* Control MMD register offsets */
> +#define MDIO_CONTROL_MMD_CTRL		0x9	/* Control */
> +
> +/* Control MMD Control defines */
> +#define MDIO_CONTROL_MMD_CTRL_MII_MMD_EN	1 /* MII MMD Enable */
> +
> +/* MII MMD registers offsets */
> +#define MDIO_MII_MMD_CTRL		0x0	/* Control */
> +#define MDIO_MII_MMD_ADV		0x4	/* AN Advertisement */
> +#define MDIO_MII_MMD_LPA		0x5	/* Link Partner Ability */

MII_BMCR, MII_ADVERTISE, MII_LPA.

> +#define MDIO_MII_MMD_DIGITAL_CTRL_1	0x8000	/* Digital Control 1 */
> +#define MDIO_MII_MMD_AN_CTRL		0x8001	/* AN Control */
> +#define MDIO_MII_MMD_AN_STAT		0x8002	/* AN Status */
> +
> +/* MII MMD Control defines */
> +#define MDIO_MII_MMD_CTRL_ANE		BIT(12)	/* AN Enable */
> +#define MDIO_MII_MMD_CTRL_LBE		BIT(14)	/* Loopback Enable */
> +#define MDIO_MII_MMD_CTRL_RANE		BIT(9)	/* Restart AN */

BMCR_ANENABLE, BMCR_LOOPBACK, BMCR_ANENABLE

If you use the standard names, developers are going to find it easier
to understand the code.


> +/* MII MMD AN Advertisement & Link Partner Ability */
> +#define MDIO_MII_MMD_HD			BIT(6)	/* Half duplex */
> +#define MDIO_MII_MMD_FD			BIT(5)	/* Full duplex */
> +#define MDIO_MII_MMD_PSE_SHIFT		7	/* Pause Ability shift */
> +#define MDIO_MII_MMD_PSE	GENMASK(8, 7)	/* Pause Ability */
> +
> +/* MII MMD Digital Control 1 defines */
> +#define MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD	BIT(0) /* SGMII PHY mode */
> +
> +/* MII MMD AN Control defines */
> +#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT	3 /* TX Config shift */
> +#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII		0x1 /* PHY side SGMII mode */
> +#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII		0x0 /* MAC side SGMII mode */
> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT	1  /* PCS Mode shift */
> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD	GENMASK(2, 1) /* PCS Mode */
> +#define AN_CTRL_PCS_MD_C37_1000BASEX	0x0	/* C37 AN for 1000BASE-X */
> +#define AN_CTRL_PCS_MD_C37_SGMII	0x2	/* C37 AN for SGMII */
> +#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN	BIT(0)	/* AN Complete Intr Enable */

> +
> +/* MII MMD AN Status defines for C37 AN SGMII Status */
> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN Complete Intr */
> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN Speed */
> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps */
> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps */
> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status */

Is these are standardized, not proprietary, consider adding them to
include/uapi/linux/mii.h so similar.

> +
> +/**
> + * dw_xpcs_init - To initialize xPCS
> + * @ndev: network device pointer
> + * @mode: PCS mode
> + * Description: this is to initialize xPCS
> + */
> +static inline void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	/* Set SGMII PHY mode control */
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				    (MII_ADDR_C45 |
> +				     (XPCS_MDIO_MII_MMD <<
> +				      MII_DEVADDR_C45_SHIFT) |
> +				     MDIO_MII_MMD_DIGITAL_CTRL_1));
> +

Why cast to u16? It return int for a reason.

> +	phydata |= MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_DIGITAL_CTRL_1),
> +		      (int)phydata);

Maybe add helpers xpcs_read() and xpcs_write()?

      Andrew
Ong Boon Leong April 25, 2019, 1:45 a.m. UTC | #2
>-----Original Message-----
>From: Andrew Lunn [mailto:andrew@lunn.ch]
>Sent: Wednesday, April 24, 2019 9:42 PM
>To: Voon, Weifeng <weifeng.voon@intel.com>
>Cc: David S. Miller <davem@davemloft.net>; netdev@vger.kernel.org; linux-
>kernel@vger.kernel.org; Ong, Boon Leong <boon.leong.ong@intel.com>;
>Kweh, Hock Leong <hock.leong.kweh@intel.com>
>Subject: Re: [PATCH 4/7] net: stmmac: introducing support for DWC xPCS
>logics
>
>On Thu, Apr 25, 2019 at 01:17:18AM +0800, Weifeng Voon wrote:
>> From: Ong Boon Leong <boon.leong.ong@intel.com>
>>
>> xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated
>> into a GbE controller that uses DWC EQoS MAC controller. An example of
>> HW configuration is shown below:-
>>
>>   <-----------------GBE Controller---------->|<--External PHY chip-->
>>
>>   +----------+         +----+    +---+               +--------------+
>>   |   EQoS   | <-GMII->|xPCS|<-->|L1 | <-- SGMII --> | External GbE |
>>   |   MAC    |         |    |    |PHY|               | PHY Chip     |
>>   +----------+         +----+    +---+               +--------------+
>>          ^               ^                                  ^
>>          |               |                                  |
>>          +---------------------MDIO-------------------------+
>>
>> xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
>> differentiate it from external PHY chip that is discovered over MDIO.
>> Therefore, xpcs_phy_addr is introduced in stmmac platform data
>> (plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
>> belongs to external PHY.
>>
>> Basic functionalities for initializing xPCS and configuring auto
>> negotiation (AN), loopback, link status, AN advertisement and Link
>> Partner ability are implemented.
>>
>> xPCS interrupt handling for C37 AN complete is also implemented.
>>
>> Tested-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
>> Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@intel.com>
>> Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
>> Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
>> Reviewed-by: Baoli Zhang <baoli.zhang@intel.com>
>> Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
>
>You need your own signed-off-by here, since you are submitting it.
>
>> ---
>>  drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h | 288
>++++++++++++++++++++++++++
>>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  17 ++
>>  include/linux/stmmac.h                        |   1 +
>>  3 files changed, 306 insertions(+)
>>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
>>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
>b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
>> new file mode 100644
>> index 0000000..446b714
>> --- /dev/null
>> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
>> @@ -0,0 +1,288 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* dw_xpcs.h: DWC Ethernet Physical Coding Sublayer Header
>> + *
>> + * Copyright (c) 2019, Intel Corporation.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of
>MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
>License for
>> + * more details.
>> + */
>
>Since you have a SPDX line, you don't need the license boilerplate.
Thanks. Will edit. 

>
>> +#ifndef __DW_XPCS_H__
>> +#define __DW_XPCS_H__
>> +
>> +#include <linux/mdio.h>
>> +#include <linux/bitops.h>
>> +#include "stmmac.h"
>> +
>> +/* XPCS Control & MII MMD Device Addresses */
>> +#define XPCS_MDIO_CONTROL_MMD	MDIO_MMD_VEND1
>> +#define XPCS_MDIO_MII_MMD	MDIO_MMD_VEND2
>> +
>> +/* Control MMD register offsets */
>> +#define MDIO_CONTROL_MMD_CTRL		0x9	/* Control */
>> +
>> +/* Control MMD Control defines */
>> +#define MDIO_CONTROL_MMD_CTRL_MII_MMD_EN	1 /* MII MMD
>Enable */
>> +
>> +/* MII MMD registers offsets */
>> +#define MDIO_MII_MMD_CTRL		0x0	/* Control */
>> +#define MDIO_MII_MMD_ADV		0x4	/* AN Advertisement
>*/
>> +#define MDIO_MII_MMD_LPA		0x5	/* Link Partner Ability
>*/
>
>MII_BMCR, MII_ADVERTISE, MII_LPA.
Ok. Will change.

>
>> +#define MDIO_MII_MMD_DIGITAL_CTRL_1	0x8000	/* Digital Control 1 */
>> +#define MDIO_MII_MMD_AN_CTRL		0x8001	/* AN Control */
>> +#define MDIO_MII_MMD_AN_STAT		0x8002	/* AN Status */
>> +
>> +/* MII MMD Control defines */
>> +#define MDIO_MII_MMD_CTRL_ANE		BIT(12)	/* AN Enable
>*/
>> +#define MDIO_MII_MMD_CTRL_LBE		BIT(14)	/* Loopback Enable */
>> +#define MDIO_MII_MMD_CTRL_RANE		BIT(9)	/* Restart AN
>*/
>
>BMCR_ANENABLE, BMCR_LOOPBACK, BMCR_ANENABLE
>
>If you use the standard names, developers are going to find it easier
>to understand the code.
Ok. Will change.

>
>
>> +/* MII MMD AN Advertisement & Link Partner Ability */
>> +#define MDIO_MII_MMD_HD			BIT(6)	/* Half duplex
>*/
>> +#define MDIO_MII_MMD_FD			BIT(5)	/* Full duplex
>*/
>> +#define MDIO_MII_MMD_PSE_SHIFT		7	/* Pause
>Ability shift */
>> +#define MDIO_MII_MMD_PSE	GENMASK(8, 7)	/* Pause Ability */
>> +
>> +/* MII MMD Digital Control 1 defines */
>> +#define MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD	BIT(0) /* SGMII
>PHY mode */
>> +
>> +/* MII MMD AN Control defines */
>> +#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT	3 /* TX Config
>shift */
>> +#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII		0x1 /* PHY
>side SGMII mode */
>> +#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII		0x0 /* MAC
>side SGMII mode */
>> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT	1  /* PCS Mode
>shift */
>> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD	GENMASK(2, 1) /* PCS
>Mode */
>> +#define AN_CTRL_PCS_MD_C37_1000BASEX	0x0	/* C37 AN for
>1000BASE-X */
>> +#define AN_CTRL_PCS_MD_C37_SGMII	0x2	/* C37 AN for SGMII */
>> +#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN	BIT(0)	/* AN
>Complete Intr Enable */
>
>> +
>> +/* MII MMD AN Status defines for C37 AN SGMII Status */
>> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN Complete Intr */
>> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
>> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
>> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN Speed */
>> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
>> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps
>*/
>> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps
>*/
>> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status */
>
>Is these are standardized, not proprietary, consider adding them to
>include/uapi/linux/mii.h so similar.

Yeah, it does look very standardized. However, per DW spec, they are
vendor-specific register set which uses MDIO_MMD_VEND2 to access.

>
>> +
>> +/**
>> + * dw_xpcs_init - To initialize xPCS
>> + * @ndev: network device pointer
>> + * @mode: PCS mode
>> + * Description: this is to initialize xPCS
>> + */
>> +static inline void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
>> +{
>> +	struct stmmac_priv *priv = netdev_priv(ndev);
>> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
>> +
>> +	/* Set SGMII PHY mode control */
>> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
>> +				    (MII_ADDR_C45 |
>> +				     (XPCS_MDIO_MII_MMD <<
>> +				      MII_DEVADDR_C45_SHIFT) |
>> +				     MDIO_MII_MMD_DIGITAL_CTRL_1));
>> +
>
>Why cast to u16? It return int for a reason.
Will change to u32 here.  

>
>> +	phydata |= MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD;
>> +
>> +	mdiobus_write(priv->mii, xpcs_phy_addr,
>> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
>> +		       MII_DEVADDR_C45_SHIFT) |
>MDIO_MII_MMD_DIGITAL_CTRL_1),
>> +		      (int)phydata);
>
>Maybe add helpers xpcs_read() and xpcs_write()?
Good suggestion. Thanks for your review. 

>
>      Andrew
Andrew Lunn April 25, 2019, 3:21 a.m. UTC | #3
> >> +/* MII MMD AN Status defines for C37 AN SGMII Status */
> >> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN Complete Intr */
> >> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
> >> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
> >> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN Speed */
> >> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
> >> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps
> >*/
> >> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps
> >*/
> >> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status */
> >
> >Is these are standardized, not proprietary, consider adding them to
> >include/uapi/linux/mii.h so similar.
> 
> Yeah, it does look very standardized. However, per DW spec, they are
> vendor-specific register set which uses MDIO_MMD_VEND2 to access.

Maybe you can go get the 802.3 standard and check section 37. If these
registers are the same, they could still be placed in mii.h. What MMD
you use is a different matter.

  Andrew
Ong Boon Leong April 25, 2019, 6:51 a.m. UTC | #4
>-----Original Message-----
>From: Andrew Lunn [mailto:andrew@lunn.ch]
>Sent: Thursday, April 25, 2019 11:21 AM
>To: Ong, Boon Leong <boon.leong.ong@intel.com>
>Cc: David S. Miller <davem@davemloft.net>; netdev@vger.kernel.org; linux-
>kernel@vger.kernel.org; Kweh, Hock Leong <hock.leong.kweh@intel.com>;
>Voon, Weifeng <weifeng.voon@intel.com>
>Subject: Re: [PATCH 4/7] net: stmmac: introducing support for DWC xPCS
>logics
>
>> >> +/* MII MMD AN Status defines for C37 AN SGMII Status */
>> >> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN
>Complete Intr */
>> >> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
>> >> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
>> >> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN
>Speed */
>> >> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
>> >> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps
>> >*/
>> >> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps
>> >*/
>> >> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status
>*/
>> >
>> >Is these are standardized, not proprietary, consider adding them to
>> >include/uapi/linux/mii.h so similar.
>>
>> Yeah, it does look very standardized. However, per DW spec, they are
>> vendor-specific register set which uses MDIO_MMD_VEND2 to access.
>
>Maybe you can go get the 802.3 standard and check section 37. If these
>registers are the same, they could still be placed in mii.h. What MMD
>you use is a different matter.
>
I cross-checked on 802.3 section 37.2.5.1 Management registers, the spec only
talks about BMSR and extended status. I also checked on 802.3 section 45.2
MDIO interface registers, section 45.2.7 AN registers, section 45.2.9 &
45.2.10 Vendor specific MMD1 & MMD2, there are no field format that
matches the above bit fields. So, it should be reasonable to park these #defines
in this local file for now.  

Thanks.
Boon Leong
Voon, Weifeng April 25, 2019, 7:06 a.m. UTC | #5
> From: Ong Boon Leong <boon.leong.ong@intel.com>
> 
> xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated into a
> GbE controller that uses DWC EQoS MAC controller. An example of HW
> configuration is shown below:-
> 
>   <-----------------GBE Controller---------->|<--External PHY chip-->
> 
>   +----------+         +----+    +---+               +--------------+
>   |   EQoS   | <-GMII->|xPCS|<-->|L1 | <-- SGMII --> | External GbE |
>   |   MAC    |         |    |    |PHY|               | PHY Chip     |
>   +----------+         +----+    +---+               +--------------+
>          ^               ^                                  ^
>          |               |                                  |
>          +---------------------MDIO-------------------------+
> 
> xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
> differentiate it from external PHY chip that is discovered over MDIO.
> Therefore, xpcs_phy_addr is introduced in stmmac platform data
> (plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
> belongs to external PHY.
> 
> Basic functionalities for initializing xPCS and configuring auto negotiation (AN),
> loopback, link status, AN advertisement and Link Partner ability are
> implemented.
> 
> xPCS interrupt handling for C37 AN complete is also implemented.
> 
> Tested-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
> Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@intel.com>
> Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
> Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
> Reviewed-by: Baoli Zhang <baoli.zhang@intel.com>
> Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h | 288
> ++++++++++++++++++++++++++
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  17 ++
>  include/linux/stmmac.h                        |   1 +
>  3 files changed, 306 insertions(+)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> new file mode 100644
> index 0000000..446b714
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> @@ -0,0 +1,288 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* dw_xpcs.h: DWC Ethernet Physical Coding Sublayer Header
> + *
> + * Copyright (c) 2019, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> +it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but
> +WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY
> +or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> +License for
> + * more details.
> + */
> +#ifndef __DW_XPCS_H__
> +#define __DW_XPCS_H__
> +
> +#include <linux/mdio.h>
> +#include <linux/bitops.h>
> +#include "stmmac.h"
> +
> +/* XPCS Control & MII MMD Device Addresses */
> +#define XPCS_MDIO_CONTROL_MMD	MDIO_MMD_VEND1
> +#define XPCS_MDIO_MII_MMD	MDIO_MMD_VEND2
> +
> +/* Control MMD register offsets */
> +#define MDIO_CONTROL_MMD_CTRL		0x9	/* Control */
> +
> +/* Control MMD Control defines */
> +#define MDIO_CONTROL_MMD_CTRL_MII_MMD_EN	1 /* MII MMD
> Enable */
> +
> +/* MII MMD registers offsets */
> +#define MDIO_MII_MMD_CTRL		0x0	/* Control */
> +#define MDIO_MII_MMD_ADV		0x4	/* AN Advertisement
> */
> +#define MDIO_MII_MMD_LPA		0x5	/* Link Partner Ability
> */
> +#define MDIO_MII_MMD_DIGITAL_CTRL_1	0x8000	/* Digital Control 1 */
> +#define MDIO_MII_MMD_AN_CTRL		0x8001	/* AN Control */
> +#define MDIO_MII_MMD_AN_STAT		0x8002	/* AN Status */
> +
> +/* MII MMD Control defines */
> +#define MDIO_MII_MMD_CTRL_ANE		BIT(12)	/* AN Enable */
> +#define MDIO_MII_MMD_CTRL_LBE		BIT(14)	/* Loopback Enable
> */
> +#define MDIO_MII_MMD_CTRL_RANE		BIT(9)	/* Restart AN
> */
> +
> +/* MII MMD AN Advertisement & Link Partner Ability */
> +#define MDIO_MII_MMD_HD			BIT(6)	/* Half duplex
> */
> +#define MDIO_MII_MMD_FD			BIT(5)	/* Full duplex
> */
> +#define MDIO_MII_MMD_PSE_SHIFT		7	/* Pause
> Ability shift */
> +#define MDIO_MII_MMD_PSE	GENMASK(8, 7)	/* Pause
> Ability */
> +
> +/* MII MMD Digital Control 1 defines */
> +#define MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD	BIT(0) /*
> SGMII PHY mode */
> +
> +/* MII MMD AN Control defines */
> +#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT	3 /* TX Config
> shift */
> +#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII		0x1 /* PHY
> side SGMII mode */
> +#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII		0x0 /* MAC
> side SGMII mode */
> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT	1  /* PCS Mode shift
> */
> +#define MDIO_MII_MMD_AN_CTRL_PCS_MD	GENMASK(2, 1) /*
> PCS Mode */
> +#define AN_CTRL_PCS_MD_C37_1000BASEX	0x0	/* C37 AN for
> 1000BASE-X */
> +#define AN_CTRL_PCS_MD_C37_SGMII	0x2	/* C37 AN for SGMII
> */
> +#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN	BIT(0)	/* AN
> Complete Intr Enable */
> +
> +/* MII MMD AN Status defines for C37 AN SGMII Status */
> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN Complete Intr
> */
> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN
> Speed */
> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps */
> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps
> */
> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status */
> +
> +/**
> + * dw_xpcs_init - To initialize xPCS
> + * @ndev: network device pointer
> + * @mode: PCS mode
> + * Description: this is to initialize xPCS  */ static inline void
> +dw_xpcs_init(struct net_device *ndev, int pcs_mode) {
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	/* Set SGMII PHY mode control */
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				    (MII_ADDR_C45 |
> +				     (XPCS_MDIO_MII_MMD <<
> +				      MII_DEVADDR_C45_SHIFT) |
> +				     MDIO_MII_MMD_DIGITAL_CTRL_1));
> +
> +	phydata |= MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) |
> MDIO_MII_MMD_DIGITAL_CTRL_1),
> +		      (int)phydata);
> +
> +	/* Set PHY side SGMII, PCS Mode & Enable C37 AN complete
> interrupt */
> +	phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				    (MII_ADDR_C45 |
> +				     (XPCS_MDIO_MII_MMD <<
> +				      MII_DEVADDR_C45_SHIFT) |
> +				     MDIO_MII_MMD_AN_CTRL));
> +
> +	phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
> +	phydata |= (((pcs_mode <<
> MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT) &
> +		    MDIO_MII_MMD_AN_CTRL_PCS_MD) |
> +		    (AN_CTRL_TX_CONF_PHY_SIDE_SGMII <<
> +		    MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT) |
> +		    MDIO_MII_MMD_AN_CTRL_AN_INTR_EN);
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) |
> MDIO_MII_MMD_AN_CTRL),
> +		      (int)phydata);
> +}
> +
> +/**
> + * dw_xpcs_rane - To restart Auto Negotiation (AN)
> + * @ndev: network device pointer
> + * @restart: to restart AN
> + * Description: this is to restart AN.
> + */
> +static inline void dw_xpcs_rane(struct net_device *ndev, bool restart)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				 MII_DEVADDR_C45_SHIFT) |
> +				 MDIO_MII_MMD_CTRL));
> +
> +	if (restart)
> +		phydata |= MDIO_MII_MMD_CTRL_RANE;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_CTRL),
> +		      (int)phydata);
> +}
> +
> +/**
> + * dw_xpcs_ctrl_ane - To program the MII MMD Control Register.
> + * @ndev: network device pointer
> + * @ane: to enable the Auto Negotiation
> + * @loopback: to cause the PHY to loopback Tx data into Rx path.
> + * Description: this is the main function to configure the MII MMD
> + * control register and init the AN Enable and select loopback.
> + */
> +static inline void dw_xpcs_ctrl_ane(struct net_device *ndev, bool ane,
> +				    bool loopback)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				 MII_DEVADDR_C45_SHIFT) |
> +				 MDIO_MII_MMD_CTRL));
> +
> +	if (ane)
> +		phydata |= (MDIO_MII_MMD_CTRL_ANE |
> MDIO_MII_MMD_CTRL_RANE);
> +
> +	if (loopback)
> +		phydata |= MDIO_MII_MMD_CTRL_LBE;
> +
> +	mdiobus_write(priv->mii, xpcs_phy_addr,
> +		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_CTRL),
> +		      (int)phydata);
> +}
> +
> +/**
> + * dw_xpcs_get_adv_lp - Get AN Advertisement and Link Partner Ability
> + * @ndev: network device pointer
> + * @adv_lp: structure to store the adv, lp status
> + * Description: this is to expose the Auto Negotiation Advertisement
> +and
> + * Link partner ability status to ethtool support.
> + */
> +static inline void dw_xpcs_get_adv_lp(struct net_device *ndev,
> +				      struct rgmii_adv *adv_lp)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +
> +	/* AN Advertisement Ability */
> +	u16 value = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				 MII_DEVADDR_C45_SHIFT) |
> +				 MDIO_MII_MMD_ADV));
> +
> +	if (value & MDIO_MII_MMD_FD)
> +		adv_lp->duplex = DUPLEX_FULL;
> +	if (value & MDIO_MII_MMD_HD)
> +		adv_lp->duplex = DUPLEX_HALF;
> +	adv_lp->pause = (u32)((value & MDIO_MII_MMD_PSE) >>
> +			      MDIO_MII_MMD_PSE_SHIFT);
> +
> +	/* Link Partner Ability */
> +	value = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +				  (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD
> <<
> +				   MII_DEVADDR_C45_SHIFT) |
> +				   MDIO_MII_MMD_LPA));
> +
> +	if (value & MDIO_MII_MMD_FD)
> +		adv_lp->lp_duplex = DUPLEX_FULL;
> +	if (value & MDIO_MII_MMD_HD)
> +		adv_lp->lp_duplex = DUPLEX_HALF;
> +	adv_lp->lp_pause = (u32)((value & MDIO_MII_MMD_PSE) >>
> +				 MDIO_MII_MMD_PSE_SHIFT);
> +}
> +
> +/**
> + * dw_xpcs_get_linkstatus - Get Link Status
> + * @an_stat: C37 AN status value
> + * @x: stmmac extra status
> + * Description: this is to read the link extra status from <C37 AN
> +SGMII
> + * status> field of MII MMD AN Status register.
> + */
> +static inline void dw_xpcs_get_linkstatus(u16 an_stat,
> +					  struct stmmac_extra_stats *x)
> +{
> +	/* Check the link status */
> +	if (an_stat & AN_STAT_C37_AN_LNKSTS) {
> +		int speed_value;
> +
> +		x->pcs_link = 1;
> +
> +		speed_value = ((an_stat & AN_STAT_C37_AN_SPEED) >>
> +				AN_STAT_C37_AN_SPEED_SHIFT);
> +		if (speed_value == AN_STAT_C37_AN_1000MBPS)
> +			x->pcs_speed = SPEED_1000;
> +		else if (speed_value == AN_STAT_C37_AN_100MBPS)
> +			x->pcs_speed = SPEED_100;
> +		else
> +			x->pcs_speed = SPEED_10;
> +
> +		if (an_stat & AN_STAT_C37_AN_FD)
> +			x->pcs_duplex = 1;
> +		else
> +			x->pcs_duplex = 0;
> +
> +		pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
> +			x->pcs_duplex ? "Full" : "Half");
> +	} else {
> +		x->pcs_link = 0;
> +		pr_info("Link is Down\n");
> +	}
> +}
> +
> +/**
> + * dw_xpcs_irq_status - Get xPCS IRQ Status
> + * @ndev: network device pointer
> + * @x: stmmac extra status
> + * Description: this is to read the xPCS IRQ status.
> + */
> +static inline int dw_xpcs_irq_status(struct net_device *ndev,
> +				     struct stmmac_extra_stats *x)
> +{
> +	struct stmmac_priv *priv = netdev_priv(ndev);
> +	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
> +	int ret = IRQ_NONE;
> +
> +	/* C37 AN status */
> +	u16 an_stat = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
> +					(MII_ADDR_C45 |
> +					 (XPCS_MDIO_MII_MMD <<
> +					  MII_DEVADDR_C45_SHIFT) |
> +					 MDIO_MII_MMD_AN_STAT));
> +
> +	if (an_stat & AN_STAT_C37_AN_CMPLT) {
> +		x->irq_pcs_ane_n++;
> +		dw_xpcs_get_linkstatus(an_stat, x);
> +
> +		/* Clear C37 AN complete status by writing zero */
> +		mdiobus_write(priv->mii, xpcs_phy_addr,
> +			      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
> +			       MII_DEVADDR_C45_SHIFT) |
> +			       MDIO_MII_MMD_AN_STAT),
> +			      0);
> +		ret = IRQ_HANDLED;
> +	}
> +
> +	return ret;
> +}
> +#endif /* __DW_XPCS_H__ */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> index 5bb0023..cb7eb48 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> @@ -310,6 +310,13 @@ struct stmmac_ops {
>  			     bool loopback);
>  	void (*pcs_rane)(void __iomem *ioaddr, bool restart);
>  	void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv
> *adv);
> +	/* xPCS calls */
> +	void (*xpcs_init)(struct net_device *ndev, int pcs_mode);
> +	void (*xpcs_ctrl_ane)(struct net_device *ndev, bool ane, bool
> loopback);
> +	void (*xpcs_rane)(struct net_device *ndev, bool restart);
> +	void (*xpcs_get_adv_lp)(struct net_device *ndev, struct rgmii_adv
> *adv);
> +	int (*xpcs_irq_status)(struct net_device *ndev,
> +			       struct stmmac_extra_stats *x);
>  	/* Safety Features */
>  	int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp);
>  	int (*safety_feat_irq_status)(struct net_device *ndev, @@ -382,6
> +389,16 @@ struct stmmac_ops {
>  	stmmac_do_void_callback(__priv, mac, pcs_rane, __args)  #define
> stmmac_pcs_get_adv_lp(__priv, __args...) \
>  	stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args)
> +#define stmmac_xpcs_init(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_init, __args) #define
> +stmmac_xpcs_ctrl_ane(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_ctrl_ane, __args)
> #define
> +stmmac_xpcs_rane(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_rane, __args) #define
> +stmmac_xpcs_get_adv_lp(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, mac, xpcs_get_adv_lp, __args)
> #define
> +stmmac_xpcs_irq_status(__priv, __args...) \
> +	stmmac_do_callback(__priv, mac, xpcs_irq_status, __args)
>  #define stmmac_safety_feat_config(__priv, __args...) \
>  	stmmac_do_callback(__priv, mac, safety_feat_config, __args)
> #define stmmac_safety_feat_irq_status(__priv, __args...) \ diff --git
> a/include/linux/stmmac.h b/include/linux/stmmac.h index 4335bd7..b00e795
> 100644
> --- a/include/linux/stmmac.h
> +++ b/include/linux/stmmac.h
> @@ -148,6 +148,7 @@ struct stmmac_txq_cfg {  struct
> plat_stmmacenet_data {
>  	int bus_id;
>  	int phy_addr;
> +	int xpcs_phy_addr;
>  	int interface;
>  	struct stmmac_mdio_bus_data *mdio_bus_data;
>  	struct device_node *phy_node;
> --
> 1.9.1

++ stmmac maintainers and c45 experts
Andrew Lunn April 25, 2019, 12:22 p.m. UTC | #6
> >> >> +/* MII MMD AN Status defines for C37 AN SGMII Status */
> >> >> +#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN
> >Complete Intr */
> >> >> +#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
> >> >> +#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
> >> >> +#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN
> >Speed */
> >> >> +#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
> >> >> +#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps
> >> >*/
> >> >> +#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps
> >> >*/
> >> >> +#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status
> >*/
> >> >
> >> >Is these are standardized, not proprietary, consider adding them to
> >> >include/uapi/linux/mii.h so similar.
> >>
> >> Yeah, it does look very standardized. However, per DW spec, they are
> >> vendor-specific register set which uses MDIO_MMD_VEND2 to access.
> >
> >Maybe you can go get the 802.3 standard and check section 37. If these
> >registers are the same, they could still be placed in mii.h. What MMD
> >you use is a different matter.
> >
> I cross-checked on 802.3 section 37.2.5.1 Management registers, the spec only
> talks about BMSR and extended status. I also checked on 802.3 section 45.2
> MDIO interface registers, section 45.2.7 AN registers, section 45.2.9 &
> 45.2.10 Vendor specific MMD1 & MMD2, there are no field format that
> matches the above bit fields. So, it should be reasonable to park these #defines
> in this local file for now.  

Thanks for checking the standards. If these don't actually represent
anything from C37, maybe you should change the name to avoid
confusion. s/C37/SGMII/g ?

	   Thanks
		Andrew
Jose Abreu April 29, 2019, 1:23 p.m. UTC | #7
From: Voon, Weifeng <weifeng.voon@intel.com>
Date: Thu, Apr 25, 2019 at 08:06:43

> > From: Ong Boon Leong <boon.leong.ong@intel.com>
> > 
> > xPCS is DWC Ethernet Physical Coding Sublayer that may be integrated into a
> > GbE controller that uses DWC EQoS MAC controller. An example of HW
> > configuration is shown below:-
> > 
> >   <-----------------GBE Controller---------->|<--External PHY chip-->
> > 
> >   +----------+         +----+    +---+               +--------------+
> >   |   EQoS   | <-GMII->|xPCS|<-->|L1 | <-- SGMII --> | External GbE |
> >   |   MAC    |         |    |    |PHY|               | PHY Chip     |
> >   +----------+         +----+    +---+               +--------------+
> >          ^               ^                                  ^
> >          |               |                                  |
> >          +---------------------MDIO-------------------------+
> > 
> > xPCS is a Clause-45 MDIO Manageable Device (MMD) and we need a way to
> > differentiate it from external PHY chip that is discovered over MDIO.
> > Therefore, xpcs_phy_addr is introduced in stmmac platform data
> > (plat_stmmacenet_data) for differentiating xPCS from 'phy_addr' that
> > belongs to external PHY.
> > 
> > Basic functionalities for initializing xPCS and configuring auto negotiation (AN),
> > loopback, link status, AN advertisement and Link Partner ability are
> > implemented.
> > 
> > xPCS interrupt handling for C37 AN complete is also implemented.
> > 
> > Tested-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
> > Reviewed-by: Chuah Kim Tatt <kim.tatt.chuah@intel.com>
> > Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
> > Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
> > Reviewed-by: Baoli Zhang <baoli.zhang@intel.com>
> > Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
> > ---
> >  drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h | 288
> > ++++++++++++++++++++++++++
> >  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  17 ++
> >  include/linux/stmmac.h                        |   1 +
> >  3 files changed, 306 insertions(+)
> >  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> > b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
> > new file mode 100644
> > index 0000000..446b714
> > --- /dev/null
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h

I would rather prefer see this as a .c file and then just export a new 
structure for HWIF because this does not belong to the MAC. Is there any 
specific reason why you added this as a .h file besides the reuse of 
callbacks across cores ?

And having inline functions everywhere seems overkill also.

Thanks,
Jose Miguel Abreu
diff mbox series

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
new file mode 100644
index 0000000..446b714
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dw_xpcs.h
@@ -0,0 +1,288 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* dw_xpcs.h: DWC Ethernet Physical Coding Sublayer Header
+ *
+ * Copyright (c) 2019, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#ifndef __DW_XPCS_H__
+#define __DW_XPCS_H__
+
+#include <linux/mdio.h>
+#include <linux/bitops.h>
+#include "stmmac.h"
+
+/* XPCS Control & MII MMD Device Addresses */
+#define XPCS_MDIO_CONTROL_MMD	MDIO_MMD_VEND1
+#define XPCS_MDIO_MII_MMD	MDIO_MMD_VEND2
+
+/* Control MMD register offsets */
+#define MDIO_CONTROL_MMD_CTRL		0x9	/* Control */
+
+/* Control MMD Control defines */
+#define MDIO_CONTROL_MMD_CTRL_MII_MMD_EN	1 /* MII MMD Enable */
+
+/* MII MMD registers offsets */
+#define MDIO_MII_MMD_CTRL		0x0	/* Control */
+#define MDIO_MII_MMD_ADV		0x4	/* AN Advertisement */
+#define MDIO_MII_MMD_LPA		0x5	/* Link Partner Ability */
+#define MDIO_MII_MMD_DIGITAL_CTRL_1	0x8000	/* Digital Control 1 */
+#define MDIO_MII_MMD_AN_CTRL		0x8001	/* AN Control */
+#define MDIO_MII_MMD_AN_STAT		0x8002	/* AN Status */
+
+/* MII MMD Control defines */
+#define MDIO_MII_MMD_CTRL_ANE		BIT(12)	/* AN Enable */
+#define MDIO_MII_MMD_CTRL_LBE		BIT(14)	/* Loopback Enable */
+#define MDIO_MII_MMD_CTRL_RANE		BIT(9)	/* Restart AN */
+
+/* MII MMD AN Advertisement & Link Partner Ability */
+#define MDIO_MII_MMD_HD			BIT(6)	/* Half duplex */
+#define MDIO_MII_MMD_FD			BIT(5)	/* Full duplex */
+#define MDIO_MII_MMD_PSE_SHIFT		7	/* Pause Ability shift */
+#define MDIO_MII_MMD_PSE	GENMASK(8, 7)	/* Pause Ability */
+
+/* MII MMD Digital Control 1 defines */
+#define MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD	BIT(0) /* SGMII PHY mode */
+
+/* MII MMD AN Control defines */
+#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT	3 /* TX Config shift */
+#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII		0x1 /* PHY side SGMII mode */
+#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII		0x0 /* MAC side SGMII mode */
+#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT	1  /* PCS Mode shift */
+#define MDIO_MII_MMD_AN_CTRL_PCS_MD	GENMASK(2, 1) /* PCS Mode */
+#define AN_CTRL_PCS_MD_C37_1000BASEX	0x0	/* C37 AN for 1000BASE-X */
+#define AN_CTRL_PCS_MD_C37_SGMII	0x2	/* C37 AN for SGMII */
+#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN	BIT(0)	/* AN Complete Intr Enable */
+
+/* MII MMD AN Status defines for C37 AN SGMII Status */
+#define AN_STAT_C37_AN_CMPLT		BIT(0)	/* AN Complete Intr */
+#define AN_STAT_C37_AN_FD		BIT(1)	/* Full Duplex */
+#define AN_STAT_C37_AN_SPEED_SHIFT	2	/* AN Speed shift */
+#define AN_STAT_C37_AN_SPEED		GENMASK(3, 2)	/* AN Speed */
+#define AN_STAT_C37_AN_10MBPS		0x0	/* 10 Mbps */
+#define AN_STAT_C37_AN_100MBPS		0x1	/* 100 Mbps */
+#define AN_STAT_C37_AN_1000MBPS		0x2	/* 1000 Mbps */
+#define AN_STAT_C37_AN_LNKSTS		BIT(4)	/* Link Status */
+
+/**
+ * dw_xpcs_init - To initialize xPCS
+ * @ndev: network device pointer
+ * @mode: PCS mode
+ * Description: this is to initialize xPCS
+ */
+static inline void dw_xpcs_init(struct net_device *ndev, int pcs_mode)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+
+	/* Set SGMII PHY mode control */
+	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+				    (MII_ADDR_C45 |
+				     (XPCS_MDIO_MII_MMD <<
+				      MII_DEVADDR_C45_SHIFT) |
+				     MDIO_MII_MMD_DIGITAL_CTRL_1));
+
+	phydata |= MDIO_MII_MMD_DIGI_CTRL_1_SGMII_PHY_MD;
+
+	mdiobus_write(priv->mii, xpcs_phy_addr,
+		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_DIGITAL_CTRL_1),
+		      (int)phydata);
+
+	/* Set PHY side SGMII, PCS Mode & Enable C37 AN complete interrupt */
+	phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+				    (MII_ADDR_C45 |
+				     (XPCS_MDIO_MII_MMD <<
+				      MII_DEVADDR_C45_SHIFT) |
+				     MDIO_MII_MMD_AN_CTRL));
+
+	phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
+	phydata |= (((pcs_mode << MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT) &
+		    MDIO_MII_MMD_AN_CTRL_PCS_MD) |
+		    (AN_CTRL_TX_CONF_PHY_SIDE_SGMII <<
+		    MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT) |
+		    MDIO_MII_MMD_AN_CTRL_AN_INTR_EN);
+
+	mdiobus_write(priv->mii, xpcs_phy_addr,
+		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_AN_CTRL),
+		      (int)phydata);
+}
+
+/**
+ * dw_xpcs_rane - To restart Auto Negotiation (AN)
+ * @ndev: network device pointer
+ * @restart: to restart AN
+ * Description: this is to restart AN.
+ */
+static inline void dw_xpcs_rane(struct net_device *ndev, bool restart)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+
+	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+				 MII_DEVADDR_C45_SHIFT) |
+				 MDIO_MII_MMD_CTRL));
+
+	if (restart)
+		phydata |= MDIO_MII_MMD_CTRL_RANE;
+
+	mdiobus_write(priv->mii, xpcs_phy_addr,
+		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_CTRL),
+		      (int)phydata);
+}
+
+/**
+ * dw_xpcs_ctrl_ane - To program the MII MMD Control Register.
+ * @ndev: network device pointer
+ * @ane: to enable the Auto Negotiation
+ * @loopback: to cause the PHY to loopback Tx data into Rx path.
+ * Description: this is the main function to configure the MII MMD
+ * control register and init the AN Enable and select loopback.
+ */
+static inline void dw_xpcs_ctrl_ane(struct net_device *ndev, bool ane,
+				    bool loopback)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+
+	u16 phydata = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+				 MII_DEVADDR_C45_SHIFT) |
+				 MDIO_MII_MMD_CTRL));
+
+	if (ane)
+		phydata |= (MDIO_MII_MMD_CTRL_ANE | MDIO_MII_MMD_CTRL_RANE);
+
+	if (loopback)
+		phydata |= MDIO_MII_MMD_CTRL_LBE;
+
+	mdiobus_write(priv->mii, xpcs_phy_addr,
+		      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+		       MII_DEVADDR_C45_SHIFT) | MDIO_MII_MMD_CTRL),
+		      (int)phydata);
+}
+
+/**
+ * dw_xpcs_get_adv_lp - Get AN Advertisement and Link Partner Ability
+ * @ndev: network device pointer
+ * @adv_lp: structure to store the adv, lp status
+ * Description: this is to expose the Auto Negotiation Advertisement and
+ * Link partner ability status to ethtool support.
+ */
+static inline void dw_xpcs_get_adv_lp(struct net_device *ndev,
+				      struct rgmii_adv *adv_lp)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+
+	/* AN Advertisement Ability */
+	u16 value = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+				(MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+				 MII_DEVADDR_C45_SHIFT) |
+				 MDIO_MII_MMD_ADV));
+
+	if (value & MDIO_MII_MMD_FD)
+		adv_lp->duplex = DUPLEX_FULL;
+	if (value & MDIO_MII_MMD_HD)
+		adv_lp->duplex = DUPLEX_HALF;
+	adv_lp->pause = (u32)((value & MDIO_MII_MMD_PSE) >>
+			      MDIO_MII_MMD_PSE_SHIFT);
+
+	/* Link Partner Ability */
+	value = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+				  (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+				   MII_DEVADDR_C45_SHIFT) |
+				   MDIO_MII_MMD_LPA));
+
+	if (value & MDIO_MII_MMD_FD)
+		adv_lp->lp_duplex = DUPLEX_FULL;
+	if (value & MDIO_MII_MMD_HD)
+		adv_lp->lp_duplex = DUPLEX_HALF;
+	adv_lp->lp_pause = (u32)((value & MDIO_MII_MMD_PSE) >>
+				 MDIO_MII_MMD_PSE_SHIFT);
+}
+
+/**
+ * dw_xpcs_get_linkstatus - Get Link Status
+ * @an_stat: C37 AN status value
+ * @x: stmmac extra status
+ * Description: this is to read the link extra status from <C37 AN SGMII
+ * status> field of MII MMD AN Status register.
+ */
+static inline void dw_xpcs_get_linkstatus(u16 an_stat,
+					  struct stmmac_extra_stats *x)
+{
+	/* Check the link status */
+	if (an_stat & AN_STAT_C37_AN_LNKSTS) {
+		int speed_value;
+
+		x->pcs_link = 1;
+
+		speed_value = ((an_stat & AN_STAT_C37_AN_SPEED) >>
+				AN_STAT_C37_AN_SPEED_SHIFT);
+		if (speed_value == AN_STAT_C37_AN_1000MBPS)
+			x->pcs_speed = SPEED_1000;
+		else if (speed_value == AN_STAT_C37_AN_100MBPS)
+			x->pcs_speed = SPEED_100;
+		else
+			x->pcs_speed = SPEED_10;
+
+		if (an_stat & AN_STAT_C37_AN_FD)
+			x->pcs_duplex = 1;
+		else
+			x->pcs_duplex = 0;
+
+		pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
+			x->pcs_duplex ? "Full" : "Half");
+	} else {
+		x->pcs_link = 0;
+		pr_info("Link is Down\n");
+	}
+}
+
+/**
+ * dw_xpcs_irq_status - Get xPCS IRQ Status
+ * @ndev: network device pointer
+ * @x: stmmac extra status
+ * Description: this is to read the xPCS IRQ status.
+ */
+static inline int dw_xpcs_irq_status(struct net_device *ndev,
+				     struct stmmac_extra_stats *x)
+{
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	int xpcs_phy_addr = priv->plat->xpcs_phy_addr;
+	int ret = IRQ_NONE;
+
+	/* C37 AN status */
+	u16 an_stat = (u16)mdiobus_read(priv->mii, xpcs_phy_addr,
+					(MII_ADDR_C45 |
+					 (XPCS_MDIO_MII_MMD <<
+					  MII_DEVADDR_C45_SHIFT) |
+					 MDIO_MII_MMD_AN_STAT));
+
+	if (an_stat & AN_STAT_C37_AN_CMPLT) {
+		x->irq_pcs_ane_n++;
+		dw_xpcs_get_linkstatus(an_stat, x);
+
+		/* Clear C37 AN complete status by writing zero */
+		mdiobus_write(priv->mii, xpcs_phy_addr,
+			      (MII_ADDR_C45 | (XPCS_MDIO_MII_MMD <<
+			       MII_DEVADDR_C45_SHIFT) |
+			       MDIO_MII_MMD_AN_STAT),
+			      0);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+#endif /* __DW_XPCS_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 5bb0023..cb7eb48 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -310,6 +310,13 @@  struct stmmac_ops {
 			     bool loopback);
 	void (*pcs_rane)(void __iomem *ioaddr, bool restart);
 	void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
+	/* xPCS calls */
+	void (*xpcs_init)(struct net_device *ndev, int pcs_mode);
+	void (*xpcs_ctrl_ane)(struct net_device *ndev, bool ane, bool loopback);
+	void (*xpcs_rane)(struct net_device *ndev, bool restart);
+	void (*xpcs_get_adv_lp)(struct net_device *ndev, struct rgmii_adv *adv);
+	int (*xpcs_irq_status)(struct net_device *ndev,
+			       struct stmmac_extra_stats *x);
 	/* Safety Features */
 	int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp);
 	int (*safety_feat_irq_status)(struct net_device *ndev,
@@ -382,6 +389,16 @@  struct stmmac_ops {
 	stmmac_do_void_callback(__priv, mac, pcs_rane, __args)
 #define stmmac_pcs_get_adv_lp(__priv, __args...) \
 	stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args)
+#define stmmac_xpcs_init(__priv, __args...) \
+	stmmac_do_void_callback(__priv, mac, xpcs_init, __args)
+#define stmmac_xpcs_ctrl_ane(__priv, __args...) \
+	stmmac_do_void_callback(__priv, mac, xpcs_ctrl_ane, __args)
+#define stmmac_xpcs_rane(__priv, __args...) \
+	stmmac_do_void_callback(__priv, mac, xpcs_rane, __args)
+#define stmmac_xpcs_get_adv_lp(__priv, __args...) \
+	stmmac_do_void_callback(__priv, mac, xpcs_get_adv_lp, __args)
+#define stmmac_xpcs_irq_status(__priv, __args...) \
+	stmmac_do_callback(__priv, mac, xpcs_irq_status, __args)
 #define stmmac_safety_feat_config(__priv, __args...) \
 	stmmac_do_callback(__priv, mac, safety_feat_config, __args)
 #define stmmac_safety_feat_irq_status(__priv, __args...) \
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 4335bd7..b00e795 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -148,6 +148,7 @@  struct stmmac_txq_cfg {
 struct plat_stmmacenet_data {
 	int bus_id;
 	int phy_addr;
+	int xpcs_phy_addr;
 	int interface;
 	struct stmmac_mdio_bus_data *mdio_bus_data;
 	struct device_node *phy_node;