1 /* 2 * B53 register access through MII registers 3 * 4 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 5 * 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. 9 * 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. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/phy.h> 21 #include <linux/module.h> 22 #include <linux/delay.h> 23 #include <linux/brcmphy.h> 24 #include <linux/rtnetlink.h> 25 #include <net/dsa.h> 26 27 #include "b53_priv.h" 28 29 /* MII registers */ 30 #define REG_MII_PAGE 0x10 /* MII Page register */ 31 #define REG_MII_ADDR 0x11 /* MII Address register */ 32 #define REG_MII_DATA0 0x18 /* MII Data register 0 */ 33 #define REG_MII_DATA1 0x19 /* MII Data register 1 */ 34 #define REG_MII_DATA2 0x1a /* MII Data register 2 */ 35 #define REG_MII_DATA3 0x1b /* MII Data register 3 */ 36 37 #define REG_MII_PAGE_ENABLE BIT(0) 38 #define REG_MII_ADDR_WRITE BIT(0) 39 #define REG_MII_ADDR_READ BIT(1) 40 41 static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) 42 { 43 int i; 44 u16 v; 45 int ret; 46 struct mii_bus *bus = dev->priv; 47 48 if (dev->current_page != page) { 49 /* set page number */ 50 v = (page << 8) | REG_MII_PAGE_ENABLE; 51 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 52 REG_MII_PAGE, v); 53 if (ret) 54 return ret; 55 dev->current_page = page; 56 } 57 58 /* set register address */ 59 v = (reg << 8) | op; 60 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v); 61 if (ret) 62 return ret; 63 64 /* check if operation completed */ 65 for (i = 0; i < 5; ++i) { 66 v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 67 REG_MII_ADDR); 68 if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) 69 break; 70 usleep_range(10, 100); 71 } 72 73 if (WARN_ON(i == 5)) 74 return -EIO; 75 76 return 0; 77 } 78 79 static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 80 { 81 struct mii_bus *bus = dev->priv; 82 int ret; 83 84 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 85 if (ret) 86 return ret; 87 88 *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 89 REG_MII_DATA0) & 0xff; 90 91 return 0; 92 } 93 94 static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 95 { 96 struct mii_bus *bus = dev->priv; 97 int ret; 98 99 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 100 if (ret) 101 return ret; 102 103 *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0); 104 105 return 0; 106 } 107 108 static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 109 { 110 struct mii_bus *bus = dev->priv; 111 int ret; 112 113 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 114 if (ret) 115 return ret; 116 117 *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0); 118 *val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 119 REG_MII_DATA1) << 16; 120 121 return 0; 122 } 123 124 static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 125 { 126 struct mii_bus *bus = dev->priv; 127 u64 temp = 0; 128 int i; 129 int ret; 130 131 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 132 if (ret) 133 return ret; 134 135 for (i = 2; i >= 0; i--) { 136 temp <<= 16; 137 temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 138 REG_MII_DATA0 + i); 139 } 140 141 *val = temp; 142 143 return 0; 144 } 145 146 static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 147 { 148 struct mii_bus *bus = dev->priv; 149 u64 temp = 0; 150 int i; 151 int ret; 152 153 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 154 if (ret) 155 return ret; 156 157 for (i = 3; i >= 0; i--) { 158 temp <<= 16; 159 temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 160 REG_MII_DATA0 + i); 161 } 162 163 *val = temp; 164 165 return 0; 166 } 167 168 static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 169 { 170 struct mii_bus *bus = dev->priv; 171 int ret; 172 173 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 174 REG_MII_DATA0, value); 175 if (ret) 176 return ret; 177 178 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 179 } 180 181 static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, 182 u16 value) 183 { 184 struct mii_bus *bus = dev->priv; 185 int ret; 186 187 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 188 REG_MII_DATA0, value); 189 if (ret) 190 return ret; 191 192 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 193 } 194 195 static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, 196 u32 value) 197 { 198 struct mii_bus *bus = dev->priv; 199 unsigned int i; 200 u32 temp = value; 201 202 for (i = 0; i < 2; i++) { 203 int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 204 REG_MII_DATA0 + i, 205 temp & 0xffff); 206 if (ret) 207 return ret; 208 temp >>= 16; 209 } 210 211 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 212 } 213 214 static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, 215 u64 value) 216 { 217 struct mii_bus *bus = dev->priv; 218 unsigned int i; 219 u64 temp = value; 220 221 for (i = 0; i < 3; i++) { 222 int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 223 REG_MII_DATA0 + i, 224 temp & 0xffff); 225 if (ret) 226 return ret; 227 temp >>= 16; 228 } 229 230 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 231 } 232 233 static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, 234 u64 value) 235 { 236 struct mii_bus *bus = dev->priv; 237 unsigned int i; 238 u64 temp = value; 239 240 for (i = 0; i < 4; i++) { 241 int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 242 REG_MII_DATA0 + i, 243 temp & 0xffff); 244 if (ret) 245 return ret; 246 temp >>= 16; 247 } 248 249 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 250 } 251 252 static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg, 253 u16 *value) 254 { 255 struct mii_bus *bus = dev->priv; 256 257 *value = mdiobus_read_nested(bus, addr, reg); 258 259 return 0; 260 } 261 262 static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg, 263 u16 value) 264 { 265 struct mii_bus *bus = dev->bus; 266 267 return mdiobus_write_nested(bus, addr, reg, value); 268 } 269 270 static const struct b53_io_ops b53_mdio_ops = { 271 .read8 = b53_mdio_read8, 272 .read16 = b53_mdio_read16, 273 .read32 = b53_mdio_read32, 274 .read48 = b53_mdio_read48, 275 .read64 = b53_mdio_read64, 276 .write8 = b53_mdio_write8, 277 .write16 = b53_mdio_write16, 278 .write32 = b53_mdio_write32, 279 .write48 = b53_mdio_write48, 280 .write64 = b53_mdio_write64, 281 .phy_read16 = b53_mdio_phy_read16, 282 .phy_write16 = b53_mdio_phy_write16, 283 }; 284 285 #define B53_BRCM_OUI_1 0x0143bc00 286 #define B53_BRCM_OUI_2 0x03625c00 287 #define B53_BRCM_OUI_3 0x00406000 288 289 static int b53_mdio_probe(struct mdio_device *mdiodev) 290 { 291 struct b53_device *dev; 292 u32 phy_id; 293 int ret; 294 295 /* allow the generic PHY driver to take over the non-management MDIO 296 * addresses 297 */ 298 if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) { 299 dev_err(&mdiodev->dev, "leaving address %d to PHY\n", 300 mdiodev->addr); 301 return -ENODEV; 302 } 303 304 /* read the first port's id */ 305 phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16; 306 phy_id |= mdiobus_read(mdiodev->bus, 0, 3); 307 308 /* BCM5325, BCM539x (OUI_1) 309 * BCM53125, BCM53128 (OUI_2) 310 * BCM5365 (OUI_3) 311 */ 312 if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && 313 (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && 314 (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) { 315 dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); 316 return -ENODEV; 317 } 318 319 /* First probe will come from SWITCH_MDIO controller on the 7445D0 320 * switch, which will conflict with the 7445 integrated switch 321 * pseudo-phy (we end-up programming both). In that case, we return 322 * -EPROBE_DEFER for the first time we get here, and wait until we come 323 * back with the slave MDIO bus which has the correct indirection 324 * layer setup 325 */ 326 if (of_machine_is_compatible("brcm,bcm7445d0") && 327 strcmp(mdiodev->bus->name, "sf2 slave mii")) 328 return -EPROBE_DEFER; 329 330 dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus); 331 if (!dev) 332 return -ENOMEM; 333 334 /* we don't use page 0xff, so force a page set */ 335 dev->current_page = 0xff; 336 dev->bus = mdiodev->bus; 337 338 dev_set_drvdata(&mdiodev->dev, dev); 339 340 ret = b53_switch_register(dev); 341 if (ret) { 342 dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret); 343 return ret; 344 } 345 346 return ret; 347 } 348 349 static void b53_mdio_remove(struct mdio_device *mdiodev) 350 { 351 struct b53_device *dev = dev_get_drvdata(&mdiodev->dev); 352 struct dsa_switch *ds = dev->ds; 353 354 dsa_unregister_switch(ds); 355 } 356 357 static const struct of_device_id b53_of_match[] = { 358 { .compatible = "brcm,bcm5325" }, 359 { .compatible = "brcm,bcm53115" }, 360 { .compatible = "brcm,bcm53125" }, 361 { .compatible = "brcm,bcm53128" }, 362 { .compatible = "brcm,bcm5365" }, 363 { .compatible = "brcm,bcm5395" }, 364 { .compatible = "brcm,bcm5397" }, 365 { .compatible = "brcm,bcm5398" }, 366 { /* sentinel */ }, 367 }; 368 MODULE_DEVICE_TABLE(of, b53_of_match); 369 370 static struct mdio_driver b53_mdio_driver = { 371 .probe = b53_mdio_probe, 372 .remove = b53_mdio_remove, 373 .mdiodrv.driver = { 374 .name = "bcm53xx", 375 .of_match_table = b53_of_match, 376 }, 377 }; 378 379 static int __init b53_mdio_driver_register(void) 380 { 381 return mdio_driver_register(&b53_mdio_driver); 382 } 383 module_init(b53_mdio_driver_register); 384 385 static void __exit b53_mdio_driver_unregister(void) 386 { 387 mdio_driver_unregister(&b53_mdio_driver); 388 } 389 module_exit(b53_mdio_driver_unregister); 390 391 MODULE_DESCRIPTION("B53 MDIO access driver"); 392 MODULE_LICENSE("Dual BSD/GPL"); 393