aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/marvell.c
diff options
context:
space:
mode:
authorAlexandr Smirnov <asmirnov@ru.mvista.com>2008-03-18 17:37:24 -0400
committerJeff Garzik <jeff@garzik.org>2008-03-25 23:16:52 -0400
commitbe937f1f89cacd833bd242c35af911b971225cf0 (patch)
tree676aa3730c39993d4a2a4e1d1b939a9ee776bfbc /drivers/net/phy/marvell.c
parentd1847a722e79bbfc557755d78f44d3e2c8ae5ea9 (diff)
Marvell PHY m88e1111 driver fix
Marvell PHY m88e1111 (not sure about other models, but think they too) works in two modes: fiber and copper. In Marvell PHY driver (that we have in current community kernels) code supported only copper mode, and this is not configurable, bits for copper mode are simply written in registers during PHY initialization. This patch adds support for both modes. Signed-off-by: Alexandr Smirnov <asmirnov@ru.mvista.com> Acked-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/phy/marvell.c')
-rw-r--r--drivers/net/phy/marvell.c129
1 files changed, 124 insertions, 5 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index f0574073a2a3..b5f4c28f6b79 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -58,9 +58,25 @@
58#define MII_M1111_RX_DELAY 0x80 58#define MII_M1111_RX_DELAY 0x80
59#define MII_M1111_TX_DELAY 0x2 59#define MII_M1111_TX_DELAY 0x2
60#define MII_M1111_PHY_EXT_SR 0x1b 60#define MII_M1111_PHY_EXT_SR 0x1b
61#define MII_M1111_HWCFG_MODE_MASK 0xf 61
62#define MII_M1111_HWCFG_MODE_RGMII 0xb 62#define MII_M1111_HWCFG_MODE_MASK 0xf
63#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb
64#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3
63#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 65#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4
66#define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000
67#define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000
68
69#define MII_M1111_COPPER 0
70#define MII_M1111_FIBER 1
71
72#define MII_M1011_PHY_STATUS 0x11
73#define MII_M1011_PHY_STATUS_1000 0x8000
74#define MII_M1011_PHY_STATUS_100 0x4000
75#define MII_M1011_PHY_STATUS_SPD_MASK 0xc000
76#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000
77#define MII_M1011_PHY_STATUS_RESOLVED 0x0800
78#define MII_M1011_PHY_STATUS_LINK 0x0400
79
64 80
65MODULE_DESCRIPTION("Marvell PHY driver"); 81MODULE_DESCRIPTION("Marvell PHY driver");
66MODULE_AUTHOR("Andy Fleming"); 82MODULE_AUTHOR("Andy Fleming");
@@ -141,12 +157,22 @@ static int marvell_config_aneg(struct phy_device *phydev)
141static int m88e1111_config_init(struct phy_device *phydev) 157static int m88e1111_config_init(struct phy_device *phydev)
142{ 158{
143 int err; 159 int err;
160 int temp;
161 int mode;
162
163 /* Enable Fiber/Copper auto selection */
164 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
165 temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
166 phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
167
168 temp = phy_read(phydev, MII_BMCR);
169 temp |= BMCR_RESET;
170 phy_write(phydev, MII_BMCR, temp);
144 171
145 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 172 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
146 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || 173 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
147 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || 174 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
148 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { 175 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
149 int temp;
150 176
151 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 177 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
152 if (temp < 0) 178 if (temp < 0)
@@ -171,7 +197,13 @@ static int m88e1111_config_init(struct phy_device *phydev)
171 return temp; 197 return temp;
172 198
173 temp &= ~(MII_M1111_HWCFG_MODE_MASK); 199 temp &= ~(MII_M1111_HWCFG_MODE_MASK);
174 temp |= MII_M1111_HWCFG_MODE_RGMII; 200
201 mode = phy_read(phydev, MII_M1111_PHY_EXT_CR);
202
203 if (mode & MII_M1111_HWCFG_FIBER_COPPER_RES)
204 temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
205 else
206 temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
175 207
176 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 208 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
177 if (err < 0) 209 if (err < 0)
@@ -262,6 +294,93 @@ static int m88e1145_config_init(struct phy_device *phydev)
262 return 0; 294 return 0;
263} 295}
264 296
297/* marvell_read_status
298 *
299 * Generic status code does not detect Fiber correctly!
300 * Description:
301 * Check the link, then figure out the current state
302 * by comparing what we advertise with what the link partner
303 * advertises. Start by checking the gigabit possibilities,
304 * then move on to 10/100.
305 */
306static int marvell_read_status(struct phy_device *phydev)
307{
308 int adv;
309 int err;
310 int lpa;
311 int status = 0;
312
313 /* Update the link, but return if there
314 * was an error */
315 err = genphy_update_link(phydev);
316 if (err)
317 return err;
318
319 if (AUTONEG_ENABLE == phydev->autoneg) {
320 status = phy_read(phydev, MII_M1011_PHY_STATUS);
321 if (status < 0)
322 return status;
323
324 lpa = phy_read(phydev, MII_LPA);
325 if (lpa < 0)
326 return lpa;
327
328 adv = phy_read(phydev, MII_ADVERTISE);
329 if (adv < 0)
330 return adv;
331
332 lpa &= adv;
333
334 if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
335 phydev->duplex = DUPLEX_FULL;
336 else
337 phydev->duplex = DUPLEX_HALF;
338
339 status = status & MII_M1011_PHY_STATUS_SPD_MASK;
340 phydev->pause = phydev->asym_pause = 0;
341
342 switch (status) {
343 case MII_M1011_PHY_STATUS_1000:
344 phydev->speed = SPEED_1000;
345 break;
346
347 case MII_M1011_PHY_STATUS_100:
348 phydev->speed = SPEED_100;
349 break;
350
351 default:
352 phydev->speed = SPEED_10;
353 break;
354 }
355
356 if (phydev->duplex == DUPLEX_FULL) {
357 phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
358 phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
359 }
360 } else {
361 int bmcr = phy_read(phydev, MII_BMCR);
362
363 if (bmcr < 0)
364 return bmcr;
365
366 if (bmcr & BMCR_FULLDPLX)
367 phydev->duplex = DUPLEX_FULL;
368 else
369 phydev->duplex = DUPLEX_HALF;
370
371 if (bmcr & BMCR_SPEED1000)
372 phydev->speed = SPEED_1000;
373 else if (bmcr & BMCR_SPEED100)
374 phydev->speed = SPEED_100;
375 else
376 phydev->speed = SPEED_10;
377
378 phydev->pause = phydev->asym_pause = 0;
379 }
380
381 return 0;
382}
383
265static struct phy_driver marvell_drivers[] = { 384static struct phy_driver marvell_drivers[] = {
266 { 385 {
267 .phy_id = 0x01410c60, 386 .phy_id = 0x01410c60,
@@ -296,7 +415,7 @@ static struct phy_driver marvell_drivers[] = {
296 .flags = PHY_HAS_INTERRUPT, 415 .flags = PHY_HAS_INTERRUPT,
297 .config_init = &m88e1111_config_init, 416 .config_init = &m88e1111_config_init,
298 .config_aneg = &marvell_config_aneg, 417 .config_aneg = &marvell_config_aneg,
299 .read_status = &genphy_read_status, 418 .read_status = &marvell_read_status,
300 .ack_interrupt = &marvell_ack_interrupt, 419 .ack_interrupt = &marvell_ack_interrupt,
301 .config_intr = &marvell_config_intr, 420 .config_intr = &marvell_config_intr,
302 .driver = { .owner = THIS_MODULE }, 421 .driver = { .owner = THIS_MODULE },