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