[U-Boot] [PATCH 1/1] ppc4xx: Add support for GPCS, SGMII and M88E1112 PHY

Stefan Roese sr at denx.de
Sat Aug 30 11:18:30 CEST 2008


Victor,

On Saturday 30 August 2008, Victor Gallardo wrote:
> This patch adds GPCS, SGMII and M88E1112 PHY support
> for the AMCC PPC460GT/EX processors.

Please find some comments below.

> Signed-off-by: Victor Gallardo <vgallardo at amcc.com>
> ---
>  cpu/ppc4xx/4xx_enet.c |  116
> ++++++++++++++++++++++++++++++++++++++++++++++++- cpu/ppc4xx/miiphy.c   |  
> 40 ++++++++++++++++-
>  include/ppc4xx_enet.h |    4 ++
>  3 files changed, 155 insertions(+), 5 deletions(-)
>
> diff --git a/cpu/ppc4xx/4xx_enet.c b/cpu/ppc4xx/4xx_enet.c
> index 8a38335..4729800 100644
> --- a/cpu/ppc4xx/4xx_enet.c
> +++ b/cpu/ppc4xx/4xx_enet.c
> @@ -198,6 +198,7 @@
>  #define BI_PHYMODE_RMII  8
>  #endif
>  #endif
> +#define BI_PHYMODE_SGMII 9
>
>  #if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
>      defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
> @@ -216,6 +217,12 @@
>  #define MAL_RX_CHAN_MUL	1
>  #endif
>
> +#if !defined(CONFIG_PHY_LESS)
> +#define CONFIG_PHY_LESS        0xFFFFFFFF /* PHY-less mode */
> +#define CONFIG_PHY_LESS_SPEED  1000
> +#define CONFIG_PHY_LESS_DUPLEX FULL
> +#endif

Could you please explain this PHY_LESS mode and especially the CONFIG_PHY_LESS 
define a little more. To what value will this be defined for Arches for 
example?

> +
> 
> /*-------------------------------------------------------------------------
>----+ * Global variables. TX and RX descriptors and buffers.
>  
> *--------------------------------------------------------------------------
>---*/ @@ -611,8 +618,19 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t *
> bis)
>
>  #if defined(CONFIG_460EX)
>  	mode = 9;
> +	mfsdr(SDR0_ETH_CFG, eth_cfg);
> +	if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
> +		((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0)) {
> +		mode = 11; /* config SGMII */
> +}

Make this a little simpler and drop the brackets (for single line statements):

	if ((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) &&
	    (eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE))
		mode = 11; /* config SGMII */

>  #else
>  	mode = 10;
> +	mfsdr(SDR0_ETH_CFG, eth_cfg);
> +	if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
> +		((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0) &&
> +		((eth_cfg & SDR0_ETH_CFG_SGMII2_ENABLE) > 0)) {
> +		mode = 12; /* config SGMII */
> +}

Same here please.

>  #endif
>
>  	/* TODO:
> @@ -635,6 +653,8 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
>  	/*
>  	 * Right now only 2*RGMII is supported. Please extend when needed.
>  	 * sr - 2008-02-19
> +	 * Add SGMII support.
> +	 * vg - 2008-07-28
>  	 */
>  	switch (mode) {
>  	case 1:
> @@ -761,6 +781,20 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
>  		bis->bi_phymode[2] = BI_PHYMODE_RGMII;
>  		bis->bi_phymode[3] = BI_PHYMODE_RGMII;
>  		break;
> +	case 11:
> +		/* 2 SGMII - 460EX */
> +		bis->bi_phymode[0] = BI_PHYMODE_SGMII;
> +		bis->bi_phymode[1] = BI_PHYMODE_SGMII;
> +		bis->bi_phymode[2] = BI_PHYMODE_NONE;
> +		bis->bi_phymode[3] = BI_PHYMODE_NONE;
> +		break;
> +	case 12:
> +		/* 3 SGMII - 460GT */
> +		bis->bi_phymode[0] = BI_PHYMODE_SGMII;
> +		bis->bi_phymode[1] = BI_PHYMODE_SGMII;
> +		bis->bi_phymode[2] = BI_PHYMODE_SGMII;
> +		bis->bi_phymode[3] = BI_PHYMODE_NONE;
> +		break;
>  	default:
>  		break;
>  	}
> @@ -945,6 +979,48 @@ static int ppc_4xx_eth_init (struct eth_device *dev,
> bd_t * bis) out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);
>  #endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */
>
> +#if defined(CONFIG_GPCS_PHY_ADDR) || defined(CONFIG_GPCS_PHY1_ADDR) || \
> +    defined(CONFIG_GPCS_PHY2_ADDR) || defined(CONFIG_GPCS_PHY3_ADDR)
> +	if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {
> +		/*
> +		 * In SGMII mode, GPCS access is needed for
> +		 * communication with the internal SGMII SerDes.
> +		 */
> +		switch (devnum) {
> +#if defined(CONFIG_GPCS_PHY_ADDR)
> +		case 0:
> +			reg = CONFIG_GPCS_PHY_ADDR;
> +			break;
> +#endif
> +#if defined(CONFIG_GPCS_PHY1_ADDR)
> +		case 1:
> +			reg = CONFIG_GPCS_PHY1_ADDR;
> +			break;
> +#endif
> +#if defined(CONFIG_GPCS_PHY2_ADDR)
> +		case 2:
> +			reg = CONFIG_GPCS_PHY2_ADDR;
> +			break;
> +#endif
> +#if defined(CONFIG_GPCS_PHY3_ADDR)
> +		case 3:
> +			reg = CONFIG_GPCS_PHY3_ADDR;
> +			break;
> +#endif
> +		}
> +
> +		mode_reg = in_be32((void *)EMAC_M1 + hw_p->hw_addr);
> +		mode_reg |= EMAC_M1_MF_1000GPCS | EMAC_M1_IPPA_SET(reg);
> +		out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);
> +
> +		/* Configure the GPCS interface */
> +		miiphy_reset(dev->name, reg);
> +		miiphy_write(dev->name, reg, 0x04, 0x8120);
> +		miiphy_write(dev->name, reg, 0x07, 0x2801);
> +		miiphy_write(dev->name, reg, 0x00, 0x0140);

Please add some comments for those "magic number" above. 

> +	}
> +#endif /* defined(CONFIG_GPCS_PHY_ADDR) */
> +
>  	/* wait for PHY to complete auto negotiation */
>  	reg_short = 0;
>  #ifndef CONFIG_CS8952_PHY
> @@ -974,6 +1050,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev,
> bd_t * bis)
>
>  	bis->bi_phynum[devnum] = reg;
>
> +	if (reg == CONFIG_PHY_LESS)
> +		goto GET_SPEED;

Don't use uppercase names for labels.

> +
>  #if defined(CONFIG_PHY_RESET)
>  	/*
>  	 * Reset the phy, only if its the first time through
> @@ -986,6 +1065,33 @@ static int ppc_4xx_eth_init (struct eth_device *dev,
> bd_t * bis) miiphy_write (dev->name, reg, 0x09, 0x0e00);
>  		miiphy_write (dev->name, reg, 0x04, 0x01e1);
>  #endif
> +#if defined(CONFIG_M88E1112_PHY)
> +		if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {
> +			/*
> +			 * Marvell 88E1112 PHY needs to have the SGMII MAC
> +			 * interace (page 2) properly configured to
> +			 * communicate with the 460EX/GT GPCS interface.
> +			 */
> +
> +			/* Set access to Page 2 */
> +			miiphy_write(dev->name, reg, 0x16, 0x0002);
> +
> +			miiphy_write(dev->name, reg, 0x00, 0x0040); /* 1Gbps */
> +			miiphy_read(dev->name, reg, 0x10, &reg_short);
> +			reg_short &= ~0x0C00; /* Preferred Media MASK */
> +			reg_short |=  0x0800; /* Preferred Media Copper */
> +			reg_short &= ~0x0380; /* Mode Select MASK */
> +			reg_short |=  0x0280; /* Mode Select Copper only */
> +			miiphy_write(dev->name, reg, 0x10, reg_short);
> +			miiphy_read(dev->name, reg, 0x1a, &reg_short);
> +			reg_short |= 0x8000; /* bypass Auto-Negotiation */
> +			miiphy_write(dev->name, reg, 0x1a, reg_short);
> +			miiphy_reset(dev->name, reg); /* reset MAC interface */
> +
> +			/* Reset access to Page 0 */
> +			miiphy_write(dev->name, reg, 0x16, 0x0000);
> +		}
> +#endif /* defined(CONFIG_M88E1112_PHY) */
>  		miiphy_reset (dev->name, reg);
>
>  #if defined(CONFIG_440GX) || \
> @@ -1080,8 +1186,14 @@ static int ppc_4xx_eth_init (struct eth_device *dev,
> bd_t * bis) }
>  #endif /* #ifndef CONFIG_CS8952_PHY */
>
> -	speed = miiphy_speed (dev->name, reg);
> -	duplex = miiphy_duplex (dev->name, reg);
> +GET_SPEED:
> +	if (reg == CONFIG_PHY_LESS) {
> +		speed = CONFIG_PHY_LESS_SPEED;
> +		duplex = CONFIG_PHY_LESS_DUPLEX;
> +	} else {
> +		speed = miiphy_speed(dev->name, reg);
> +		duplex = miiphy_duplex(dev->name, reg);
> +	}
>
>  	if (hw_p->print_speed) {
>  		hw_p->print_speed = 0;
> diff --git a/cpu/ppc4xx/miiphy.c b/cpu/ppc4xx/miiphy.c
> index c882720..abc88f7 100644
> --- a/cpu/ppc4xx/miiphy.c
> +++ b/cpu/ppc4xx/miiphy.c
> @@ -180,8 +180,10 @@ int phy_setup_aneg (char *devname, unsigned char addr)
>   *
>   * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
>   * return EMAC0 offset here
> + * vg: For 460EX/460GT if internal GPCS PHY address is specified
> + * return appropriate EMAC offset
>   */
> -unsigned int miiphy_getemac_offset (void)
> +unsigned int miiphy_getemac_offset(u8 addr)
>  {
>  #if (defined(CONFIG_440) && \
>      !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
> @@ -233,6 +235,38 @@ unsigned int miiphy_getemac_offset (void)
>  		return 0x100;
>  #endif
>
> +#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
> +	u32 mode_reg;
> +	u32 eoffset = 0;

Nitpick: Please add empty line after variable declarations.

> +	switch (addr) {
> +#if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
> +	case CONFIG_GPCS_PHY1_ADDR:
> +		mode_reg = in_be32((void *)EMAC_M1 + 0x100);
> +		if (addr == EMAC_M1_IPPA_GET(mode_reg))
> +			eoffset = 0x100;
> +		break;
> +#endif
> +#if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
> +	case CONFIG_GPCS_PHY2_ADDR:
> +		mode_reg = in_be32((void *)EMAC_M1 + 0x300);
> +		if (addr == EMAC_M1_IPPA_GET(mode_reg))
> +			eoffset = 0x300;
> +		break;
> +#endif
> +#if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
> +	case CONFIG_GPCS_PHY3_ADDR:
> +		mode_reg = in_be32((void *)EMAC_M1 + 0x400);
> +		if (addr == EMAC_M1_IPPA_GET(mode_reg))
> +			eoffset = 0x400;
> +		break;
> +#endif
> +	default:
> +		eoffset = 0;
> +		break;
> +	}
> +	return eoffset;
> +#endif
> +
>  	return 0;
>  #endif
>  }
> @@ -262,7 +296,7 @@ static int emac_miiphy_command(u8 addr, u8 reg, int
> cmd, u16 value) u32 emac_reg;
>  	u32 sta_reg;
>
> -	emac_reg = miiphy_getemac_offset();
> +	emac_reg = miiphy_getemac_offset(addr);
>
>  	/* wait for completion */
>  	if (emac_miiphy_wait(emac_reg) != 0)
> @@ -311,7 +345,7 @@ int emac4xx_miiphy_read (char *devname, unsigned char
> addr, unsigned char reg, unsigned long sta_reg;
>  	unsigned long emac_reg;
>
> -	emac_reg = miiphy_getemac_offset ();
> +	emac_reg = miiphy_getemac_offset(addr);
>
>  	if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
>  		return -1;
> diff --git a/include/ppc4xx_enet.h b/include/ppc4xx_enet.h
> index b74c6fc..689b056 100644
> --- a/include/ppc4xx_enet.h
> +++ b/include/ppc4xx_enet.h
> @@ -376,6 +376,7 @@ typedef struct emac_4xx_hw_st {
>  #define EMAC_M1_APP		(0x08000000)
>  #define EMAC_M1_RSVD		(0x06000000)
>  #define EMAC_M1_IST		(0x01000000)
> +#define EMAC_M1_MF_1000GPCS	(0x00C00000)
>  #define EMAC_M1_MF_1000MBPS	(0x00800000)	/* 0's for 10MBPS */
>  #define EMAC_M1_MF_100MBPS	(0x00400000)
>  #define EMAC_M1_RFS_MASK	(0x00380000)
> @@ -394,6 +395,9 @@ typedef struct emac_4xx_hw_st {
>  #define EMAC_M1_MWSW		(0x00007000)
>  #define EMAC_M1_JUMBO_ENABLE	(0x00000800)
>  #define EMAC_M1_IPPA		(0x000007c0)
> +#define EMAC_M1_IPPA_SET(id)	(((id) & 0x1f) << 6)
> +#define EMAC_M1_IPPA_GET(id)	(((id) >> 6) & 0x1f)
> +
>  #define EMAC_M1_OBCI_GT100	(0x00000020)
>  #define EMAC_M1_OBCI_100	(0x00000018)
>  #define EMAC_M1_OBCI_83		(0x00000010)

Please clean up and resubmit.

Thanks.

Best regards,
Stefan

=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
=====================================================================


More information about the U-Boot mailing list