root/drivers/net/dsa/b53/b53_mdio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. b53_mdio_op
  2. b53_mdio_read8
  3. b53_mdio_read16
  4. b53_mdio_read32
  5. b53_mdio_read48
  6. b53_mdio_read64
  7. b53_mdio_write8
  8. b53_mdio_write16
  9. b53_mdio_write32
  10. b53_mdio_write48
  11. b53_mdio_write64
  12. b53_mdio_phy_read16
  13. b53_mdio_phy_write16
  14. b53_mdio_probe
  15. b53_mdio_remove

   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 #define B53_BRCM_OUI_4  0x01410c00
 289 
 290 static int b53_mdio_probe(struct mdio_device *mdiodev)
 291 {
 292         struct b53_device *dev;
 293         u32 phy_id;
 294         int ret;
 295 
 296         /* allow the generic PHY driver to take over the non-management MDIO
 297          * addresses
 298          */
 299         if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) {
 300                 dev_err(&mdiodev->dev, "leaving address %d to PHY\n",
 301                         mdiodev->addr);
 302                 return -ENODEV;
 303         }
 304 
 305         /* read the first port's id */
 306         phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16;
 307         phy_id |= mdiobus_read(mdiodev->bus, 0, 3);
 308 
 309         /* BCM5325, BCM539x (OUI_1)
 310          * BCM53125, BCM53128 (OUI_2)
 311          * BCM5365 (OUI_3)
 312          */
 313         if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 &&
 314             (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 &&
 315             (phy_id & 0xfffffc00) != B53_BRCM_OUI_3 &&
 316             (phy_id & 0xfffffc00) != B53_BRCM_OUI_4) {
 317                 dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id);
 318                 return -ENODEV;
 319         }
 320 
 321         /* First probe will come from SWITCH_MDIO controller on the 7445D0
 322          * switch, which will conflict with the 7445 integrated switch
 323          * pseudo-phy (we end-up programming both). In that case, we return
 324          * -EPROBE_DEFER for the first time we get here, and wait until we come
 325          * back with the slave MDIO bus which has the correct indirection
 326          * layer setup
 327          */
 328         if (of_machine_is_compatible("brcm,bcm7445d0") &&
 329             strcmp(mdiodev->bus->name, "sf2 slave mii"))
 330                 return -EPROBE_DEFER;
 331 
 332         dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus);
 333         if (!dev)
 334                 return -ENOMEM;
 335 
 336         /* we don't use page 0xff, so force a page set */
 337         dev->current_page = 0xff;
 338         dev->bus = mdiodev->bus;
 339 
 340         dev_set_drvdata(&mdiodev->dev, dev);
 341 
 342         ret = b53_switch_register(dev);
 343         if (ret) {
 344                 dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret);
 345                 return ret;
 346         }
 347 
 348         return ret;
 349 }
 350 
 351 static void b53_mdio_remove(struct mdio_device *mdiodev)
 352 {
 353         struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
 354         struct dsa_switch *ds = dev->ds;
 355 
 356         dsa_unregister_switch(ds);
 357 }
 358 
 359 static const struct of_device_id b53_of_match[] = {
 360         { .compatible = "brcm,bcm5325" },
 361         { .compatible = "brcm,bcm53115" },
 362         { .compatible = "brcm,bcm53125" },
 363         { .compatible = "brcm,bcm53128" },
 364         { .compatible = "brcm,bcm5365" },
 365         { .compatible = "brcm,bcm5389" },
 366         { .compatible = "brcm,bcm5395" },
 367         { .compatible = "brcm,bcm5397" },
 368         { .compatible = "brcm,bcm5398" },
 369         { /* sentinel */ },
 370 };
 371 MODULE_DEVICE_TABLE(of, b53_of_match);
 372 
 373 static struct mdio_driver b53_mdio_driver = {
 374         .probe  = b53_mdio_probe,
 375         .remove = b53_mdio_remove,
 376         .mdiodrv.driver = {
 377                 .name = "bcm53xx",
 378                 .of_match_table = b53_of_match,
 379         },
 380 };
 381 mdio_module_driver(b53_mdio_driver);
 382 
 383 MODULE_DESCRIPTION("B53 MDIO access driver");
 384 MODULE_LICENSE("Dual BSD/GPL");

/* [<][>][^][v][top][bottom][index][help] */