X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fnet%2Fphy%2Fmarvell.c;h=9437c3bbccd3bdc1695441673c289cc975445751;hb=62118b7b0183d29755a101a6a5b88dee11c5f94b;hp=bd1cdc4f11d63ea56b13b77ea283d9aa61a680bd;hpb=9082eeac5de1335d663016668c9b89c290f5c79b;p=u-boot diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index bd1cdc4f11..9437c3bbcc 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1,24 +1,10 @@ /* * Marvell PHY drivers * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ * * Copyright 2010-2011 Freescale Semiconductor, Inc. * author Andy Fleming - * */ #include #include @@ -43,6 +29,24 @@ #define MIIM_88E1111_PHY_LED_DIRECT 0x4100 #define MIIM_88E1111_PHY_LED_COMBINE 0x411C +/* 88E1111 Extended PHY Specific Control Register */ +#define MIIM_88E1111_PHY_EXT_CR 0x14 +#define MIIM_88E1111_RX_DELAY 0x80 +#define MIIM_88E1111_TX_DELAY 0x2 + +/* 88E1111 Extended PHY Specific Status Register */ +#define MIIM_88E1111_PHY_EXT_SR 0x1b +#define MIIM_88E1111_HWCFG_MODE_MASK 0xf +#define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb +#define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3 +#define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4 +#define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9 +#define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000 +#define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000 + +#define MIIM_88E1111_COPPER 0 +#define MIIM_88E1111_FIBER 1 + /* 88E1118 PHY defines */ #define MIIM_88E1118_PHY_PAGE 22 #define MIIM_88E1118_PHY_LED_PAGE 3 @@ -71,6 +75,12 @@ #define MIIM_88E1149_PHY_PAGE 29 +/* 88E1310 PHY defines */ +#define MIIM_88E1310_PHY_LED_CTRL 16 +#define MIIM_88E1310_PHY_IRQ_EN 18 +#define MIIM_88E1310_PHY_RGMII_CTRL 21 +#define MIIM_88E1310_PHY_PAGE 22 + /* Marvell 88E1011S */ static int m88e1011s_config(struct phy_device *phydev) { @@ -162,19 +172,102 @@ static int m88e1011s_startup(struct phy_device *phydev) static int m88e1111s_config(struct phy_device *phydev) { int reg; + int timeout; if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { - reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1b); - reg = (reg & 0xfff0) | 0xb; - phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, reg); - } else { - phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, 0x1f); + reg = phy_read(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) { + reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + reg &= ~MIIM_88E1111_TX_DELAY; + reg |= MIIM_88E1111_RX_DELAY; + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + reg &= ~MIIM_88E1111_RX_DELAY; + reg |= MIIM_88E1111_TX_DELAY; + } + + phy_write(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); + + reg = phy_read(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); + + reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); + + if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES) + reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII; + else + reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII; + + phy_write(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); } - phy_write(phydev, MDIO_DEVAD_NONE, 0x14, 0x0cd2); + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + reg = phy_read(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); + + reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); + reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; + reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; + + phy_write(phydev, MDIO_DEVAD_NONE, + MIIM_88E1111_PHY_EXT_SR, reg); + } + + if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { + reg = phy_read(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); + reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); + phy_write(phydev, + MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); + + reg = phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_88E1111_PHY_EXT_SR); + reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | + MIIM_88E1111_HWCFG_FIBER_COPPER_RES); + reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; + phy_write(phydev, MDIO_DEVAD_NONE, + MIIM_88E1111_PHY_EXT_SR, reg); + + /* soft reset */ + timeout = 1000; + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + udelay(1000); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + while ((reg & BMCR_RESET) && --timeout) { + udelay(1000); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + } + if (!timeout) + printf("%s: phy soft reset timeout\n", __func__); + + reg = phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_88E1111_PHY_EXT_SR); + reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | + MIIM_88E1111_HWCFG_FIBER_COPPER_RES); + reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI | + MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; + phy_write(phydev, MDIO_DEVAD_NONE, + MIIM_88E1111_PHY_EXT_SR, reg); + } + + /* soft reset */ + timeout = 1000; + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + udelay(1000); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + while ((reg & BMCR_RESET) && --timeout) { + udelay(1000); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + } + if (!timeout) + printf("%s: phy soft reset timeout\n", __func__); genphy_config_aneg(phydev); @@ -183,6 +276,57 @@ static int m88e1111s_config(struct phy_device *phydev) return 0; } +/** + * m88e1518_phy_writebits - write bits to a register + */ +void m88e1518_phy_writebits(struct phy_device *phydev, + u8 reg_num, u16 offset, u16 len, u16 data) +{ + u16 reg, mask; + + if ((len + offset) >= 16) + mask = 0 - (1 << offset); + else + mask = (1 << (len + offset)) - (1 << offset); + + reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num); + + reg &= ~mask; + reg |= data << offset; + + phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg); +} + +static int m88e1518_config(struct phy_device *phydev) +{ + /* + * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 + * /88E1514 Rev A0, Errata Section 3.1 + */ + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff); /* page 0xff */ + phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B); + phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144); + phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28); + phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146); + phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233); + phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D); + phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C); + phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159); + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); /* reg page 0 */ + phy_write(phydev, MDIO_DEVAD_NONE, 22, 18); /* reg page 18 */ + /* Write HWCFG_MODE = SGMII to Copper */ + m88e1518_phy_writebits(phydev, 20, 0, 3, 1); + + /* Phy reset */ + m88e1518_phy_writebits(phydev, 20, 15, 1, 1); + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0); /* reg page 18 */ + udelay(100); + } + + return m88e1111s_config(phydev); +} + /* Marvell 88E1118 */ static int m88e1118_config(struct phy_device *phydev) { @@ -293,6 +437,37 @@ static int m88e1149_config(struct phy_device *phydev) return 0; } +/* Marvell 88E1310 */ +static int m88e1310_config(struct phy_device *phydev) +{ + u16 reg; + + /* LED link and activity */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL); + reg = (reg & ~0xf) | 0x1; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg); + + /* Set LED2/INT to INT mode, low active */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN); + reg = (reg & 0x77ff) | 0x0880; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg); + + /* Set RGMII delay */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL); + reg |= 0x0030; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg); + + /* Ensure to return to page 0 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); + + genphy_config_aneg(phydev); + phy_reset(phydev); + + return 0; +} static struct phy_driver M88E1011S_driver = { .name = "Marvell 88E1011S", @@ -324,6 +499,16 @@ static struct phy_driver M88E1118_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1118R_driver = { + .name = "Marvell 88E1118R", + .uid = 0x1410e40, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1118_config, + .startup = &m88e1118_startup, + .shutdown = &genphy_shutdown, +}; + static struct phy_driver M88E1121R_driver = { .name = "Marvell 88E1121R", .uid = 0x1410cb0, @@ -354,14 +539,37 @@ static struct phy_driver M88E1149S_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1518_driver = { + .name = "Marvell 88E1518", + .uid = 0x1410dd1, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1518_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1310_driver = { + .name = "Marvell 88E1310", + .uid = 0x01410e90, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1310_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { + phy_register(&M88E1310_driver); phy_register(&M88E1149S_driver); phy_register(&M88E1145_driver); phy_register(&M88E1121R_driver); phy_register(&M88E1118_driver); + phy_register(&M88E1118R_driver); phy_register(&M88E1111S_driver); phy_register(&M88E1011S_driver); + phy_register(&M88E1518_driver); return 0; }