ppc4xx: Add support for GPCS, SGMII and M88E1112 PHY
This patch adds GPCS, SGMII and M88E1112 PHY support for the AMCC PPC460GT/EX processors. Signed-off-by: Victor Gallardo <vgallardo@amcc.com> Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
parent
f6b6c45840
commit
78d7823689
@ -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,52 @@
|
||||
#define MAL_RX_CHAN_MUL 1
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------+
|
||||
* Fixed PHY (PHY-less) support for Ethernet Ports.
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Some boards do not have a PHY for each ethernet port. These ports
|
||||
* are known as Fixed PHY (or PHY-less) ports. For such ports, set
|
||||
* the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and
|
||||
* then define CFG_FIXED_PHY_PORTS to define what the speed and
|
||||
* duplex should be for these ports in the board configuration
|
||||
* file.
|
||||
*
|
||||
* For Example:
|
||||
* #define CONFIG_FIXED_PHY 0xFFFFFFFF
|
||||
*
|
||||
* #define CONFIG_PHY_ADDR CONFIG_FIXED_PHY
|
||||
* #define CONFIG_PHY1_ADDR 1
|
||||
* #define CONFIG_PHY2_ADDR CONFIG_FIXED_PHY
|
||||
* #define CONFIG_PHY3_ADDR 3
|
||||
*
|
||||
* #define CFG_FIXED_PHY_PORT(devnum,speed,duplex) \
|
||||
* {devnum, speed, duplex},
|
||||
*
|
||||
* #define CFG_FIXED_PHY_PORTS \
|
||||
* CFG_FIXED_PHY_PORT(0,1000,FULL) \
|
||||
* CFG_FIXED_PHY_PORT(2,100,HALF)
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_FIXED_PHY
|
||||
#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
|
||||
#endif
|
||||
|
||||
#ifndef CFG_FIXED_PHY_PORTS
|
||||
#define CFG_FIXED_PHY_PORTS /* default is an empty array */
|
||||
#endif
|
||||
|
||||
struct fixed_phy_port {
|
||||
unsigned int devnum; /* ethernet port */
|
||||
unsigned int speed; /* specified speed 10,100 or 1000 */
|
||||
unsigned int duplex; /* specified duplex FULL or HALF */
|
||||
};
|
||||
|
||||
static const struct fixed_phy_port fixed_phy_port[] = {
|
||||
CFG_FIXED_PHY_PORTS /* defined in board configuration file */
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* Global variables. TX and RX descriptors and buffers.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
@ -611,8 +658,17 @@ 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 */
|
||||
#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 */
|
||||
#endif
|
||||
|
||||
/* TODO:
|
||||
@ -635,6 +691,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 +819,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 +1017,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 GPCS interface to recommended setting for SGMII */
|
||||
miiphy_reset(dev->name, reg);
|
||||
miiphy_write(dev->name, reg, 0x04, 0x8120); /* AsymPause, FDX */
|
||||
miiphy_write(dev->name, reg, 0x07, 0x2801); /* msg_pg, toggle */
|
||||
miiphy_write(dev->name, reg, 0x00, 0x0140); /* 1Gbps, FDX */
|
||||
}
|
||||
#endif /* defined(CONFIG_GPCS_PHY_ADDR) */
|
||||
|
||||
/* wait for PHY to complete auto negotiation */
|
||||
reg_short = 0;
|
||||
#ifndef CONFIG_CS8952_PHY
|
||||
@ -974,6 +1088,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
|
||||
|
||||
bis->bi_phynum[devnum] = reg;
|
||||
|
||||
if (reg == CONFIG_FIXED_PHY)
|
||||
goto get_speed;
|
||||
|
||||
#if defined(CONFIG_PHY_RESET)
|
||||
/*
|
||||
* Reset the phy, only if its the first time through
|
||||
@ -986,6 +1103,27 @@ 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, 0x1a, ®_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 +1218,25 @@ 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_FIXED_PHY) {
|
||||
for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
|
||||
if (devnum == fixed_phy_port[i].devnum) {
|
||||
speed = fixed_phy_port[i].speed;
|
||||
duplex = fixed_phy_port[i].duplex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(fixed_phy_port)) {
|
||||
printf("ERROR: PHY (%s) not configured correctly!\n",
|
||||
dev->name);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
speed = miiphy_speed(dev->name, reg);
|
||||
duplex = miiphy_duplex(dev->name, reg);
|
||||
}
|
||||
|
||||
if (hw_p->print_speed) {
|
||||
hw_p->print_speed = 0;
|
||||
|
@ -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,39 @@ unsigned int miiphy_getemac_offset (void)
|
||||
return 0x100;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
u32 mode_reg;
|
||||
u32 eoffset = 0;
|
||||
|
||||
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 +297,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 +346,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;
|
||||
|
@ -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,8 @@ 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)
|
||||
|
Loading…
Reference in New Issue
Block a user