diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/marvell.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index def19d7c53ef..e8b9c53c304b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/ethtool.h> | 30 | #include <linux/ethtool.h> |
31 | #include <linux/phy.h> | 31 | #include <linux/phy.h> |
32 | #include <linux/marvell_phy.h> | 32 | #include <linux/marvell_phy.h> |
33 | #include <linux/of.h> | ||
33 | 34 | ||
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
@@ -187,6 +188,87 @@ static int marvell_config_aneg(struct phy_device *phydev) | |||
187 | return 0; | 188 | return 0; |
188 | } | 189 | } |
189 | 190 | ||
191 | #ifdef CONFIG_OF_MDIO | ||
192 | /* | ||
193 | * Set and/or override some configuration registers based on the | ||
194 | * marvell,reg-init property stored in the of_node for the phydev. | ||
195 | * | ||
196 | * marvell,reg-init = <reg-page reg mask value>,...; | ||
197 | * | ||
198 | * There may be one or more sets of <reg-page reg mask value>: | ||
199 | * | ||
200 | * reg-page: which register bank to use. | ||
201 | * reg: the register. | ||
202 | * mask: if non-zero, ANDed with existing register value. | ||
203 | * value: ORed with the masked value and written to the regiser. | ||
204 | * | ||
205 | */ | ||
206 | static int marvell_of_reg_init(struct phy_device *phydev) | ||
207 | { | ||
208 | const __be32 *paddr; | ||
209 | int len, i, saved_page, current_page, page_changed, ret; | ||
210 | |||
211 | if (!phydev->dev.of_node) | ||
212 | return 0; | ||
213 | |||
214 | paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len); | ||
215 | if (!paddr || len < (4 * sizeof(*paddr))) | ||
216 | return 0; | ||
217 | |||
218 | saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); | ||
219 | if (saved_page < 0) | ||
220 | return saved_page; | ||
221 | page_changed = 0; | ||
222 | current_page = saved_page; | ||
223 | |||
224 | ret = 0; | ||
225 | len /= sizeof(*paddr); | ||
226 | for (i = 0; i < len - 3; i += 4) { | ||
227 | u16 reg_page = be32_to_cpup(paddr + i); | ||
228 | u16 reg = be32_to_cpup(paddr + i + 1); | ||
229 | u16 mask = be32_to_cpup(paddr + i + 2); | ||
230 | u16 val_bits = be32_to_cpup(paddr + i + 3); | ||
231 | int val; | ||
232 | |||
233 | if (reg_page != current_page) { | ||
234 | current_page = reg_page; | ||
235 | page_changed = 1; | ||
236 | ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); | ||
237 | if (ret < 0) | ||
238 | goto err; | ||
239 | } | ||
240 | |||
241 | val = 0; | ||
242 | if (mask) { | ||
243 | val = phy_read(phydev, reg); | ||
244 | if (val < 0) { | ||
245 | ret = val; | ||
246 | goto err; | ||
247 | } | ||
248 | val &= mask; | ||
249 | } | ||
250 | val |= val_bits; | ||
251 | |||
252 | ret = phy_write(phydev, reg, val); | ||
253 | if (ret < 0) | ||
254 | goto err; | ||
255 | |||
256 | } | ||
257 | err: | ||
258 | if (page_changed) { | ||
259 | i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); | ||
260 | if (ret == 0) | ||
261 | ret = i; | ||
262 | } | ||
263 | return ret; | ||
264 | } | ||
265 | #else | ||
266 | static int marvell_of_reg_init(struct phy_device *phydev) | ||
267 | { | ||
268 | return 0; | ||
269 | } | ||
270 | #endif /* CONFIG_OF_MDIO */ | ||
271 | |||
190 | static int m88e1121_config_aneg(struct phy_device *phydev) | 272 | static int m88e1121_config_aneg(struct phy_device *phydev) |
191 | { | 273 | { |
192 | int err, oldpage, mscr; | 274 | int err, oldpage, mscr; |
@@ -369,6 +451,9 @@ static int m88e1111_config_init(struct phy_device *phydev) | |||
369 | return err; | 451 | return err; |
370 | } | 452 | } |
371 | 453 | ||
454 | err = marvell_of_reg_init(phydev); | ||
455 | if (err < 0) | ||
456 | return err; | ||
372 | 457 | ||
373 | err = phy_write(phydev, MII_BMCR, BMCR_RESET); | 458 | err = phy_write(phydev, MII_BMCR, BMCR_RESET); |
374 | if (err < 0) | 459 | if (err < 0) |
@@ -421,6 +506,10 @@ static int m88e1118_config_init(struct phy_device *phydev) | |||
421 | if (err < 0) | 506 | if (err < 0) |
422 | return err; | 507 | return err; |
423 | 508 | ||
509 | err = marvell_of_reg_init(phydev); | ||
510 | if (err < 0) | ||
511 | return err; | ||
512 | |||
424 | /* Reset address */ | 513 | /* Reset address */ |
425 | err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); | 514 | err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); |
426 | if (err < 0) | 515 | if (err < 0) |
@@ -447,6 +536,10 @@ static int m88e1149_config_init(struct phy_device *phydev) | |||
447 | if (err < 0) | 536 | if (err < 0) |
448 | return err; | 537 | return err; |
449 | 538 | ||
539 | err = marvell_of_reg_init(phydev); | ||
540 | if (err < 0) | ||
541 | return err; | ||
542 | |||
450 | /* Reset address */ | 543 | /* Reset address */ |
451 | err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); | 544 | err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); |
452 | if (err < 0) | 545 | if (err < 0) |
@@ -518,6 +611,10 @@ static int m88e1145_config_init(struct phy_device *phydev) | |||
518 | } | 611 | } |
519 | } | 612 | } |
520 | 613 | ||
614 | err = marvell_of_reg_init(phydev); | ||
615 | if (err < 0) | ||
616 | return err; | ||
617 | |||
521 | return 0; | 618 | return 0; |
522 | } | 619 | } |
523 | 620 | ||