2 * B53 register access through MII registers
4 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <linux/kernel.h>
20 #include <linux/phy.h>
21 #include <linux/module.h>
25 #define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */
28 #define REG_MII_PAGE 0x10 /* MII Page register */
29 #define REG_MII_ADDR 0x11 /* MII Address register */
30 #define REG_MII_DATA0 0x18 /* MII Data register 0 */
31 #define REG_MII_DATA1 0x19 /* MII Data register 1 */
32 #define REG_MII_DATA2 0x1a /* MII Data register 2 */
33 #define REG_MII_DATA3 0x1b /* MII Data register 3 */
35 #define REG_MII_PAGE_ENABLE BIT(0)
36 #define REG_MII_ADDR_WRITE BIT(0)
37 #define REG_MII_ADDR_READ BIT(1)
39 static int b53_mdio_op(struct b53_device
*dev
, u8 page
, u8 reg
, u16 op
)
44 struct mii_bus
*bus
= dev
->priv
;
46 if (dev
->current_page
!= page
) {
48 v
= (page
<< 8) | REG_MII_PAGE_ENABLE
;
49 ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_PAGE
, v
);
52 dev
->current_page
= page
;
55 /* set register address */
57 ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_ADDR
, v
);
61 /* check if operation completed */
62 for (i
= 0; i
< 5; ++i
) {
63 v
= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_ADDR
);
64 if (!(v
& (REG_MII_ADDR_WRITE
| REG_MII_ADDR_READ
)))
66 usleep_range(10, 100);
75 static int b53_mdio_read8(struct b53_device
*dev
, u8 page
, u8 reg
, u8
*val
)
77 struct mii_bus
*bus
= dev
->priv
;
80 ret
= b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_READ
);
84 *val
= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
) & 0xff;
89 static int b53_mdio_read16(struct b53_device
*dev
, u8 page
, u8 reg
, u16
*val
)
91 struct mii_bus
*bus
= dev
->priv
;
94 ret
= b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_READ
);
98 *val
= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
);
103 static int b53_mdio_read32(struct b53_device
*dev
, u8 page
, u8 reg
, u32
*val
)
105 struct mii_bus
*bus
= dev
->priv
;
108 ret
= b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_READ
);
112 *val
= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
);
113 *val
|= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_DATA1
) << 16;
118 static int b53_mdio_read48(struct b53_device
*dev
, u8 page
, u8 reg
, u64
*val
)
120 struct mii_bus
*bus
= dev
->priv
;
125 ret
= b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_READ
);
129 for (i
= 2; i
>= 0; i
--) {
131 temp
|= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
+ i
);
139 static int b53_mdio_read64(struct b53_device
*dev
, u8 page
, u8 reg
, u64
*val
)
141 struct mii_bus
*bus
= dev
->priv
;
146 ret
= b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_READ
);
150 for (i
= 3; i
>= 0; i
--) {
152 temp
|= mdiobus_read(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
+ i
);
160 static int b53_mdio_write8(struct b53_device
*dev
, u8 page
, u8 reg
, u8 value
)
162 struct mii_bus
*bus
= dev
->priv
;
165 ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
, value
);
169 return b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_WRITE
);
172 static int b53_mdio_write16(struct b53_device
*dev
, u8 page
, u8 reg
,
175 struct mii_bus
*bus
= dev
->priv
;
178 ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
, value
);
182 return b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_WRITE
);
185 static int b53_mdio_write32(struct b53_device
*dev
, u8 page
, u8 reg
,
188 struct mii_bus
*bus
= dev
->priv
;
192 for (i
= 0; i
< 2; i
++) {
193 int ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
+ i
,
200 return b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_WRITE
);
204 static int b53_mdio_write48(struct b53_device
*dev
, u8 page
, u8 reg
,
207 struct mii_bus
*bus
= dev
->priv
;
211 for (i
= 0; i
< 3; i
++) {
212 int ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
+ i
,
219 return b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_WRITE
);
223 static int b53_mdio_write64(struct b53_device
*dev
, u8 page
, u8 reg
,
226 struct mii_bus
*bus
= dev
->priv
;
230 for (i
= 0; i
< 4; i
++) {
231 int ret
= mdiobus_write(bus
, B53_PSEUDO_PHY
, REG_MII_DATA0
+ i
,
238 return b53_mdio_op(dev
, page
, reg
, REG_MII_ADDR_WRITE
);
241 static int b53_mdio_phy_read16(struct b53_device
*dev
, int addr
, u8 reg
,
244 struct mii_bus
*bus
= dev
->priv
;
246 *value
= mdiobus_read(bus
, addr
, reg
);
251 static int b53_mdio_phy_write16(struct b53_device
*dev
, int addr
, u8 reg
,
254 struct mii_bus
*bus
= dev
->priv
;
256 return mdiobus_write(bus
, addr
, reg
, value
);
259 static struct b53_io_ops b53_mdio_ops
= {
260 .read8
= b53_mdio_read8
,
261 .read16
= b53_mdio_read16
,
262 .read32
= b53_mdio_read32
,
263 .read48
= b53_mdio_read48
,
264 .read64
= b53_mdio_read64
,
265 .write8
= b53_mdio_write8
,
266 .write16
= b53_mdio_write16
,
267 .write32
= b53_mdio_write32
,
268 .write48
= b53_mdio_write48
,
269 .write64
= b53_mdio_write64
,
270 .phy_read16
= b53_mdio_phy_read16
,
271 .phy_write16
= b53_mdio_phy_write16
,
274 static int b53_phy_probe(struct phy_device
*phydev
)
276 struct b53_device
*dev
;
279 /* allow the generic phy driver to take over */
280 if (phydev
->mdio
.addr
!= B53_PSEUDO_PHY
&& phydev
->mdio
.addr
!= 0)
283 dev
= b53_swconfig_switch_alloc(&phydev
->mdio
.dev
, &b53_mdio_ops
, phydev
->mdio
.bus
);
287 dev
->current_page
= 0xff;
288 dev
->priv
= phydev
->mdio
.bus
;
289 dev
->ops
= &b53_mdio_ops
;
291 mutex_init(&dev
->reg_mutex
);
293 ret
= b53_swconfig_switch_detect(dev
);
297 linkmode_zero(phydev
->supported
);
298 if (is5325(dev
) || is5365(dev
))
299 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT
, phydev
->supported
);
301 linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT
, phydev
->supported
);
303 linkmode_copy(phydev
->advertising
, phydev
->supported
);
305 ret
= b53_swconfig_switch_register(dev
);
307 dev_err(dev
->dev
, "failed to register switch: %i\n", ret
);
316 static int b53_phy_config_init(struct phy_device
*phydev
)
318 struct b53_device
*dev
= phydev
->priv
;
320 /* we don't use page 0xff, so force a page set */
321 dev
->current_page
= 0xff;
322 /* force the ethX as alias */
323 dev
->sw_dev
.alias
= phydev
->attached_dev
->name
;
328 static void b53_phy_remove(struct phy_device
*phydev
)
330 struct b53_device
*priv
= phydev
->priv
;
335 b53_switch_remove(priv
);
340 static int b53_phy_config_aneg(struct phy_device
*phydev
)
345 static int b53_phy_read_status(struct phy_device
*phydev
)
347 struct b53_device
*priv
= phydev
->priv
;
349 if (is5325(priv
) || is5365(priv
))
352 phydev
->speed
= 1000;
354 phydev
->duplex
= DUPLEX_FULL
;
356 phydev
->state
= PHY_RUNNING
;
358 netif_carrier_on(phydev
->attached_dev
);
359 phydev
->adjust_link(phydev
->attached_dev
);
364 /* BCM5325, BCM539x */
365 static struct phy_driver b53_phy_driver_id1
= {
366 .phy_id
= 0x0143bc00,
367 .name
= "Broadcom B53 (1)",
368 .phy_id_mask
= 0x1ffffc00,
370 .probe
= b53_phy_probe
,
371 .remove
= b53_phy_remove
,
372 .config_aneg
= b53_phy_config_aneg
,
373 .config_init
= b53_phy_config_init
,
374 .read_status
= b53_phy_read_status
,
377 /* BCM53125, BCM53128 */
378 static struct phy_driver b53_phy_driver_id2
= {
379 .phy_id
= 0x03625c00,
380 .name
= "Broadcom B53 (2)",
381 .phy_id_mask
= 0x1ffffc00,
383 .probe
= b53_phy_probe
,
384 .remove
= b53_phy_remove
,
385 .config_aneg
= b53_phy_config_aneg
,
386 .config_init
= b53_phy_config_init
,
387 .read_status
= b53_phy_read_status
,
391 static struct phy_driver b53_phy_driver_id3
= {
392 .phy_id
= 0x00406300,
393 .name
= "Broadcom B53 (3)",
394 .phy_id_mask
= 0x1fffff00,
396 .probe
= b53_phy_probe
,
397 .remove
= b53_phy_remove
,
398 .config_aneg
= b53_phy_config_aneg
,
399 .config_init
= b53_phy_config_init
,
400 .read_status
= b53_phy_read_status
,
403 int __init
b53_phy_driver_register(void)
407 ret
= phy_driver_register(&b53_phy_driver_id1
, THIS_MODULE
);
411 ret
= phy_driver_register(&b53_phy_driver_id2
, THIS_MODULE
);
415 ret
= phy_driver_register(&b53_phy_driver_id3
, THIS_MODULE
);
419 phy_driver_unregister(&b53_phy_driver_id2
);
421 phy_driver_unregister(&b53_phy_driver_id1
);
425 void __exit
b53_phy_driver_unregister(void)
427 phy_driver_unregister(&b53_phy_driver_id3
);
428 phy_driver_unregister(&b53_phy_driver_id2
);
429 phy_driver_unregister(&b53_phy_driver_id1
);
432 module_init(b53_phy_driver_register
);
433 module_exit(b53_phy_driver_unregister
);
435 MODULE_DESCRIPTION("B53 MDIO access driver");
436 MODULE_LICENSE("Dual BSD/GPL");