const char *error)
{
if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
+ EMAC_FTR_460EX_PHY_CLK_FIX |
EMAC_FTR_440EP_PHY_CLK_FIX))
DBG(dev, "%s" NL, error);
else if (net_ratelimit())
{
return phy_mode == PHY_MODE_GMII ||
phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_SGMII ||
phy_mode == PHY_MODE_TBI ||
phy_mode == PHY_MODE_RTBI;
}
static inline int emac_phy_gpcs(int phy_mode)
{
- return phy_mode == PHY_MODE_TBI ||
+ return phy_mode == PHY_MODE_SGMII ||
+ phy_mode == PHY_MODE_TBI ||
phy_mode == PHY_MODE_RTBI;
}
emac_tx_disable(dev);
}
+#ifdef CONFIG_PPC_DCR_NATIVE
+ /* Enable internal clock source */
+ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ 0, SDR0_ETH_CFG_ECS << dev->cell_index);
+#endif
+
out_be32(&p->mr0, EMAC_MR0_SRST);
while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
--n;
+#ifdef CONFIG_PPC_DCR_NATIVE
+ /* Enable external clock source */
+ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+#endif
+
if (n) {
dev->reset_failed = 0;
return 0;
switch (dev->phy.speed) {
case SPEED_1000:
if (emac_phy_gpcs(dev->phy.mode)) {
- mr1 |= EMAC_MR1_MF_1000GPCS |
- EMAC_MR1_MF_IPPA(dev->phy.address);
+ mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA(
+ (dev->phy.gpcs_address != 0xffffffff) ?
+ dev->phy.gpcs_address : dev->phy.address);
/* Put some arbitrary OUI, Manuf & Rev IDs so we can
* identify this GPCS PHY later.
out_be32(&p->iser, r);
/* We need to take GPCS PHY out of isolate mode after EMAC reset */
- if (emac_phy_gpcs(dev->phy.mode))
- emac_mii_reset_phy(&dev->phy);
+ if (emac_phy_gpcs(dev->phy.mode)) {
+ if (dev->phy.gpcs_address != 0xffffffff)
+ emac_mii_reset_gpcs(&dev->phy);
+ else
+ emac_mii_reset_phy(&dev->phy);
+ }
return 0;
}
struct emac_instance *dev = netdev_priv(ndev);
int res;
- res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
+ res = __emac_mdio_read((dev->mdio_instance &&
+ dev->phy.gpcs_address != id) ?
+ dev->mdio_instance : dev,
(u8) id, (u8) reg);
return res;
}
{
struct emac_instance *dev = netdev_priv(ndev);
- __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
+ __emac_mdio_write((dev->mdio_instance &&
+ dev->phy.gpcs_address != id) ?
+ dev->mdio_instance : dev,
(u8) id, (u8) reg, (u16) val);
}
* XXX I probably should move these settings to the dev tree
*/
dev->phy.address = -1;
- dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
+ dev->phy.features = SUPPORTED_MII;
+ if (emac_phy_supports_gige(dev->phy_mode))
+ dev->phy.features |= SUPPORTED_1000baseT_Full;
+ else
+ dev->phy.features |= SUPPORTED_100baseT_Full;
dev->phy.pause = 1;
return 0;
* Note that the busy_phy_map is currently global
* while it should probably be per-ASIC...
*/
- dev->phy.address = dev->cell_index;
+ dev->phy.gpcs_address = dev->gpcs_address;
+ if (dev->phy.gpcs_address == 0xffffffff)
+ dev->phy.address = dev->cell_index;
}
emac_configure(dev);
dev->phy_address = 0xffffffff;
if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
dev->phy_map = 0xffffffff;
+ if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0))
+ dev->gpcs_address = 0xffffffff;
if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
return -ENXIO;
if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
/* Check EMAC version */
if (of_device_is_compatible(np, "ibm,emac4sync")) {
dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC);
+ if (of_device_is_compatible(np, "ibm,emac-460ex") ||
+ of_device_is_compatible(np, "ibm,emac-460gt"))
+ dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX;
} else if (of_device_is_compatible(np, "ibm,emac4")) {
dev->features |= EMAC_FTR_EMAC4;
if (of_device_is_compatible(np, "ibm,emac-440gx"))
ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+ if (dev->phy_mode == PHY_MODE_SGMII)
+ printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);
+
if (dev->phy.address >= 0)
printk("%s: found %s PHY (0x%02x)\n", ndev->name,
dev->phy.def->name, dev->phy.address);
phy->mdio_write(phy->dev, phy->address, reg, val);
}
+static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
+{
+ return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
+}
+
+static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
+{
+ phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
+}
+
int emac_mii_reset_phy(struct mii_phy *phy)
{
int val;
return limit <= 0;
}
+int emac_mii_reset_gpcs(struct mii_phy *phy)
+{
+ int val;
+ int limit = 10000;
+
+ val = gpcs_phy_read(phy, MII_BMCR);
+ val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
+ val |= BMCR_RESET;
+ gpcs_phy_write(phy, MII_BMCR, val);
+
+ udelay(300);
+
+ while (limit--) {
+ val = gpcs_phy_read(phy, MII_BMCR);
+ if (val >= 0 && (val & BMCR_RESET) == 0)
+ break;
+ udelay(10);
+ }
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
+
+ if (limit > 0 && phy->mode == PHY_MODE_SGMII) {
+ /* Configure GPCS interface to recommended setting for SGMII */
+ gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
+ gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
+ gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */
+ }
+
+ return limit <= 0;
+}
+
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
{
int ctl, adv;
return 0;
}
+static int m88e1112_init(struct mii_phy *phy)
+{
+ /*
+ * Marvell 88E1112 PHY needs to have the SGMII MAC
+ * interace (page 2) properly configured to
+ * communicate with the 460EX/GT GPCS interface.
+ */
+
+ u16 reg_short;
+
+ pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);
+
+ /* Set access to Page 2 */
+ phy_write(phy, 0x16, 0x0002);
+
+ phy_write(phy, 0x00, 0x0040); /* 1Gbps */
+ reg_short = (u16)(phy_read(phy, 0x1a));
+ reg_short |= 0x8000; /* bypass Auto-Negotiation */
+ phy_write(phy, 0x1a, reg_short);
+ emac_mii_reset_phy(phy); /* reset MAC interface */
+
+ /* Reset access to Page 0 */
+ phy_write(phy, 0x16, 0x0000);
+
+ return 0;
+}
+
static int et1011c_init(struct mii_phy *phy)
{
u16 reg_short;
.ops = &m88e1111_phy_ops,
};
+static struct mii_phy_ops m88e1112_phy_ops = {
+ .init = m88e1112_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def m88e1112_phy_def = {
+ .phy_id = 0x01410C90,
+ .phy_id_mask = 0x0ffffff0,
+ .name = "Marvell 88E1112 Ethernet",
+ .ops = &m88e1112_phy_ops,
+};
+
static struct mii_phy_def *mii_phy_table[] = {
&et1011c_phy_def,
&cis8201_phy_def,
&bcm5248_phy_def,
&m88e1111_phy_def,
+ &m88e1112_phy_def,
&genmii_phy_def,
NULL
};