0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/kernel.h>
0020 #include <linux/phy.h>
0021 #include <linux/module.h>
0022 #include <linux/delay.h>
0023 #include <linux/brcmphy.h>
0024 #include <linux/rtnetlink.h>
0025 #include <net/dsa.h>
0026
0027 #include "b53_priv.h"
0028
0029
0030 #define REG_MII_PAGE 0x10
0031 #define REG_MII_ADDR 0x11
0032 #define REG_MII_DATA0 0x18
0033 #define REG_MII_DATA1 0x19
0034 #define REG_MII_DATA2 0x1a
0035 #define REG_MII_DATA3 0x1b
0036
0037 #define REG_MII_PAGE_ENABLE BIT(0)
0038 #define REG_MII_ADDR_WRITE BIT(0)
0039 #define REG_MII_ADDR_READ BIT(1)
0040
0041 static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
0042 {
0043 int i;
0044 u16 v;
0045 int ret;
0046 struct mii_bus *bus = dev->priv;
0047
0048 if (dev->current_page != page) {
0049
0050 v = (page << 8) | REG_MII_PAGE_ENABLE;
0051 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0052 REG_MII_PAGE, v);
0053 if (ret)
0054 return ret;
0055 dev->current_page = page;
0056 }
0057
0058
0059 v = (reg << 8) | op;
0060 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v);
0061 if (ret)
0062 return ret;
0063
0064
0065 for (i = 0; i < 5; ++i) {
0066 v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0067 REG_MII_ADDR);
0068 if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
0069 break;
0070 usleep_range(10, 100);
0071 }
0072
0073 if (WARN_ON(i == 5))
0074 return -EIO;
0075
0076 return 0;
0077 }
0078
0079 static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
0080 {
0081 struct mii_bus *bus = dev->priv;
0082 int ret;
0083
0084 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
0085 if (ret)
0086 return ret;
0087
0088 *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0089 REG_MII_DATA0) & 0xff;
0090
0091 return 0;
0092 }
0093
0094 static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
0095 {
0096 struct mii_bus *bus = dev->priv;
0097 int ret;
0098
0099 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
0100 if (ret)
0101 return ret;
0102
0103 *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
0104
0105 return 0;
0106 }
0107
0108 static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
0109 {
0110 struct mii_bus *bus = dev->priv;
0111 int ret;
0112
0113 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
0114 if (ret)
0115 return ret;
0116
0117 *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
0118 *val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0119 REG_MII_DATA1) << 16;
0120
0121 return 0;
0122 }
0123
0124 static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
0125 {
0126 struct mii_bus *bus = dev->priv;
0127 u64 temp = 0;
0128 int i;
0129 int ret;
0130
0131 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
0132 if (ret)
0133 return ret;
0134
0135 for (i = 2; i >= 0; i--) {
0136 temp <<= 16;
0137 temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0138 REG_MII_DATA0 + i);
0139 }
0140
0141 *val = temp;
0142
0143 return 0;
0144 }
0145
0146 static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
0147 {
0148 struct mii_bus *bus = dev->priv;
0149 u64 temp = 0;
0150 int i;
0151 int ret;
0152
0153 ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
0154 if (ret)
0155 return ret;
0156
0157 for (i = 3; i >= 0; i--) {
0158 temp <<= 16;
0159 temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0160 REG_MII_DATA0 + i);
0161 }
0162
0163 *val = temp;
0164
0165 return 0;
0166 }
0167
0168 static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
0169 {
0170 struct mii_bus *bus = dev->priv;
0171 int ret;
0172
0173 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0174 REG_MII_DATA0, value);
0175 if (ret)
0176 return ret;
0177
0178 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
0179 }
0180
0181 static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
0182 u16 value)
0183 {
0184 struct mii_bus *bus = dev->priv;
0185 int ret;
0186
0187 ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0188 REG_MII_DATA0, value);
0189 if (ret)
0190 return ret;
0191
0192 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
0193 }
0194
0195 static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
0196 u32 value)
0197 {
0198 struct mii_bus *bus = dev->priv;
0199 unsigned int i;
0200 u32 temp = value;
0201
0202 for (i = 0; i < 2; i++) {
0203 int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0204 REG_MII_DATA0 + i,
0205 temp & 0xffff);
0206 if (ret)
0207 return ret;
0208 temp >>= 16;
0209 }
0210
0211 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
0212 }
0213
0214 static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
0215 u64 value)
0216 {
0217 struct mii_bus *bus = dev->priv;
0218 unsigned int i;
0219 u64 temp = value;
0220
0221 for (i = 0; i < 3; i++) {
0222 int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0223 REG_MII_DATA0 + i,
0224 temp & 0xffff);
0225 if (ret)
0226 return ret;
0227 temp >>= 16;
0228 }
0229
0230 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
0231 }
0232
0233 static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
0234 u64 value)
0235 {
0236 struct mii_bus *bus = dev->priv;
0237 unsigned int i;
0238 u64 temp = value;
0239
0240 for (i = 0; i < 4; i++) {
0241 int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
0242 REG_MII_DATA0 + i,
0243 temp & 0xffff);
0244 if (ret)
0245 return ret;
0246 temp >>= 16;
0247 }
0248
0249 return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
0250 }
0251
0252 static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg,
0253 u16 *value)
0254 {
0255 struct mii_bus *bus = dev->priv;
0256
0257 *value = mdiobus_read_nested(bus, addr, reg);
0258
0259 return 0;
0260 }
0261
0262 static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg,
0263 u16 value)
0264 {
0265 struct mii_bus *bus = dev->bus;
0266
0267 return mdiobus_write_nested(bus, addr, reg, value);
0268 }
0269
0270 static const struct b53_io_ops b53_mdio_ops = {
0271 .read8 = b53_mdio_read8,
0272 .read16 = b53_mdio_read16,
0273 .read32 = b53_mdio_read32,
0274 .read48 = b53_mdio_read48,
0275 .read64 = b53_mdio_read64,
0276 .write8 = b53_mdio_write8,
0277 .write16 = b53_mdio_write16,
0278 .write32 = b53_mdio_write32,
0279 .write48 = b53_mdio_write48,
0280 .write64 = b53_mdio_write64,
0281 .phy_read16 = b53_mdio_phy_read16,
0282 .phy_write16 = b53_mdio_phy_write16,
0283 };
0284
0285 #define B53_BRCM_OUI_1 0x0143bc00
0286 #define B53_BRCM_OUI_2 0x03625c00
0287 #define B53_BRCM_OUI_3 0x00406000
0288 #define B53_BRCM_OUI_4 0x01410c00
0289
0290 static int b53_mdio_probe(struct mdio_device *mdiodev)
0291 {
0292 struct b53_device *dev;
0293 u32 phy_id;
0294 int ret;
0295
0296
0297
0298
0299 if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) {
0300 dev_err(&mdiodev->dev, "leaving address %d to PHY\n",
0301 mdiodev->addr);
0302 return -ENODEV;
0303 }
0304
0305
0306 phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16;
0307 phy_id |= mdiobus_read(mdiodev->bus, 0, 3);
0308
0309
0310
0311
0312
0313 if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 &&
0314 (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 &&
0315 (phy_id & 0xfffffc00) != B53_BRCM_OUI_3 &&
0316 (phy_id & 0xfffffc00) != B53_BRCM_OUI_4) {
0317 dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id);
0318 return -ENODEV;
0319 }
0320
0321
0322
0323
0324
0325
0326
0327
0328 if (of_machine_is_compatible("brcm,bcm7445d0") &&
0329 strcmp(mdiodev->bus->name, "sf2 slave mii"))
0330 return -EPROBE_DEFER;
0331
0332 dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus);
0333 if (!dev)
0334 return -ENOMEM;
0335
0336
0337 dev->current_page = 0xff;
0338 dev->bus = mdiodev->bus;
0339
0340 dev_set_drvdata(&mdiodev->dev, dev);
0341
0342 ret = b53_switch_register(dev);
0343 if (ret) {
0344 dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret);
0345 return ret;
0346 }
0347
0348 return ret;
0349 }
0350
0351 static void b53_mdio_remove(struct mdio_device *mdiodev)
0352 {
0353 struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
0354
0355 if (!dev)
0356 return;
0357
0358 b53_switch_remove(dev);
0359
0360 dev_set_drvdata(&mdiodev->dev, NULL);
0361 }
0362
0363 static void b53_mdio_shutdown(struct mdio_device *mdiodev)
0364 {
0365 struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
0366
0367 if (!dev)
0368 return;
0369
0370 b53_switch_shutdown(dev);
0371
0372 dev_set_drvdata(&mdiodev->dev, NULL);
0373 }
0374
0375 static const struct of_device_id b53_of_match[] = {
0376 { .compatible = "brcm,bcm5325" },
0377 { .compatible = "brcm,bcm53115" },
0378 { .compatible = "brcm,bcm53125" },
0379 { .compatible = "brcm,bcm53128" },
0380 { .compatible = "brcm,bcm5365" },
0381 { .compatible = "brcm,bcm5389" },
0382 { .compatible = "brcm,bcm5395" },
0383 { .compatible = "brcm,bcm5397" },
0384 { .compatible = "brcm,bcm5398" },
0385 { },
0386 };
0387 MODULE_DEVICE_TABLE(of, b53_of_match);
0388
0389 static struct mdio_driver b53_mdio_driver = {
0390 .probe = b53_mdio_probe,
0391 .remove = b53_mdio_remove,
0392 .shutdown = b53_mdio_shutdown,
0393 .mdiodrv.driver = {
0394 .name = "bcm53xx",
0395 .of_match_table = b53_of_match,
0396 },
0397 };
0398 mdio_module_driver(b53_mdio_driver);
0399
0400 MODULE_DESCRIPTION("B53 MDIO access driver");
0401 MODULE_LICENSE("Dual BSD/GPL");