0001
0002
0003
0004
0005
0006
0007 #include <linux/delay.h>
0008 #include <linux/etherdevice.h>
0009 #include <linux/jiffies.h>
0010 #include <linux/list.h>
0011 #include <linux/module.h>
0012 #include <linux/netdevice.h>
0013 #include <linux/phy.h>
0014 #include <net/dsa.h>
0015 #include "mv88e6060.h"
0016
0017 static int reg_read(struct mv88e6060_priv *priv, int addr, int reg)
0018 {
0019 return mdiobus_read_nested(priv->bus, priv->sw_addr + addr, reg);
0020 }
0021
0022 static int reg_write(struct mv88e6060_priv *priv, int addr, int reg, u16 val)
0023 {
0024 return mdiobus_write_nested(priv->bus, priv->sw_addr + addr, reg, val);
0025 }
0026
0027 static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr)
0028 {
0029 int ret;
0030
0031 ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID);
0032 if (ret >= 0) {
0033 if (ret == PORT_SWITCH_ID_6060)
0034 return "Marvell 88E6060 (A0)";
0035 if (ret == PORT_SWITCH_ID_6060_R1 ||
0036 ret == PORT_SWITCH_ID_6060_R2)
0037 return "Marvell 88E6060 (B0)";
0038 if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060)
0039 return "Marvell 88E6060";
0040 }
0041
0042 return NULL;
0043 }
0044
0045 static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds,
0046 int port,
0047 enum dsa_tag_protocol m)
0048 {
0049 return DSA_TAG_PROTO_TRAILER;
0050 }
0051
0052 static int mv88e6060_switch_reset(struct mv88e6060_priv *priv)
0053 {
0054 int i;
0055 int ret;
0056 unsigned long timeout;
0057
0058
0059 for (i = 0; i < MV88E6060_PORTS; i++) {
0060 ret = reg_read(priv, REG_PORT(i), PORT_CONTROL);
0061 if (ret < 0)
0062 return ret;
0063 ret = reg_write(priv, REG_PORT(i), PORT_CONTROL,
0064 ret & ~PORT_CONTROL_STATE_MASK);
0065 if (ret)
0066 return ret;
0067 }
0068
0069
0070 usleep_range(2000, 4000);
0071
0072
0073 ret = reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL,
0074 GLOBAL_ATU_CONTROL_SWRESET |
0075 GLOBAL_ATU_CONTROL_LEARNDIS);
0076 if (ret)
0077 return ret;
0078
0079
0080 timeout = jiffies + 1 * HZ;
0081 while (time_before(jiffies, timeout)) {
0082 ret = reg_read(priv, REG_GLOBAL, GLOBAL_STATUS);
0083 if (ret < 0)
0084 return ret;
0085
0086 if (ret & GLOBAL_STATUS_INIT_READY)
0087 break;
0088
0089 usleep_range(1000, 2000);
0090 }
0091 if (time_after(jiffies, timeout))
0092 return -ETIMEDOUT;
0093
0094 return 0;
0095 }
0096
0097 static int mv88e6060_setup_global(struct mv88e6060_priv *priv)
0098 {
0099 int ret;
0100
0101
0102
0103
0104
0105 ret = reg_write(priv, REG_GLOBAL, GLOBAL_CONTROL,
0106 GLOBAL_CONTROL_MAX_FRAME_1536);
0107 if (ret)
0108 return ret;
0109
0110
0111
0112 return reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL,
0113 GLOBAL_ATU_CONTROL_LEARNDIS);
0114 }
0115
0116 static int mv88e6060_setup_port(struct mv88e6060_priv *priv, int p)
0117 {
0118 int addr = REG_PORT(p);
0119 int ret;
0120
0121 if (dsa_is_unused_port(priv->ds, p))
0122 return 0;
0123
0124
0125
0126
0127
0128
0129 ret = reg_write(priv, addr, PORT_CONTROL,
0130 dsa_is_cpu_port(priv->ds, p) ?
0131 PORT_CONTROL_TRAILER |
0132 PORT_CONTROL_INGRESS_MODE |
0133 PORT_CONTROL_STATE_FORWARDING :
0134 PORT_CONTROL_STATE_FORWARDING);
0135 if (ret)
0136 return ret;
0137
0138
0139
0140
0141
0142
0143 ret = reg_write(priv, addr, PORT_VLAN_MAP,
0144 ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
0145 (dsa_is_cpu_port(priv->ds, p) ?
0146 dsa_user_ports(priv->ds) :
0147 BIT(dsa_to_port(priv->ds, p)->cpu_dp->index)));
0148 if (ret)
0149 return ret;
0150
0151
0152
0153
0154
0155
0156 return reg_write(priv, addr, PORT_ASSOC_VECTOR, BIT(p));
0157 }
0158
0159 static int mv88e6060_setup_addr(struct mv88e6060_priv *priv)
0160 {
0161 u8 addr[ETH_ALEN];
0162 int ret;
0163 u16 val;
0164
0165 eth_random_addr(addr);
0166
0167 val = addr[0] << 8 | addr[1];
0168
0169
0170
0171
0172 val &= 0xfeff;
0173
0174 ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_01, val);
0175 if (ret)
0176 return ret;
0177
0178 ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_23,
0179 (addr[2] << 8) | addr[3]);
0180 if (ret)
0181 return ret;
0182
0183 return reg_write(priv, REG_GLOBAL, GLOBAL_MAC_45,
0184 (addr[4] << 8) | addr[5]);
0185 }
0186
0187 static int mv88e6060_setup(struct dsa_switch *ds)
0188 {
0189 struct mv88e6060_priv *priv = ds->priv;
0190 int ret;
0191 int i;
0192
0193 priv->ds = ds;
0194
0195 ret = mv88e6060_switch_reset(priv);
0196 if (ret < 0)
0197 return ret;
0198
0199
0200
0201 ret = mv88e6060_setup_global(priv);
0202 if (ret < 0)
0203 return ret;
0204
0205 ret = mv88e6060_setup_addr(priv);
0206 if (ret < 0)
0207 return ret;
0208
0209 for (i = 0; i < MV88E6060_PORTS; i++) {
0210 ret = mv88e6060_setup_port(priv, i);
0211 if (ret < 0)
0212 return ret;
0213 }
0214
0215 return 0;
0216 }
0217
0218 static int mv88e6060_port_to_phy_addr(int port)
0219 {
0220 if (port >= 0 && port < MV88E6060_PORTS)
0221 return port;
0222 return -1;
0223 }
0224
0225 static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum)
0226 {
0227 struct mv88e6060_priv *priv = ds->priv;
0228 int addr;
0229
0230 addr = mv88e6060_port_to_phy_addr(port);
0231 if (addr == -1)
0232 return 0xffff;
0233
0234 return reg_read(priv, addr, regnum);
0235 }
0236
0237 static int
0238 mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
0239 {
0240 struct mv88e6060_priv *priv = ds->priv;
0241 int addr;
0242
0243 addr = mv88e6060_port_to_phy_addr(port);
0244 if (addr == -1)
0245 return 0xffff;
0246
0247 return reg_write(priv, addr, regnum, val);
0248 }
0249
0250 static const struct dsa_switch_ops mv88e6060_switch_ops = {
0251 .get_tag_protocol = mv88e6060_get_tag_protocol,
0252 .setup = mv88e6060_setup,
0253 .phy_read = mv88e6060_phy_read,
0254 .phy_write = mv88e6060_phy_write,
0255 };
0256
0257 static int mv88e6060_probe(struct mdio_device *mdiodev)
0258 {
0259 struct device *dev = &mdiodev->dev;
0260 struct mv88e6060_priv *priv;
0261 struct dsa_switch *ds;
0262 const char *name;
0263
0264 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0265 if (!priv)
0266 return -ENOMEM;
0267
0268 priv->bus = mdiodev->bus;
0269 priv->sw_addr = mdiodev->addr;
0270
0271 name = mv88e6060_get_name(priv->bus, priv->sw_addr);
0272 if (!name)
0273 return -ENODEV;
0274
0275 dev_info(dev, "switch %s detected\n", name);
0276
0277 ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
0278 if (!ds)
0279 return -ENOMEM;
0280
0281 ds->dev = dev;
0282 ds->num_ports = MV88E6060_PORTS;
0283 ds->priv = priv;
0284 ds->dev = dev;
0285 ds->ops = &mv88e6060_switch_ops;
0286
0287 dev_set_drvdata(dev, ds);
0288
0289 return dsa_register_switch(ds);
0290 }
0291
0292 static void mv88e6060_remove(struct mdio_device *mdiodev)
0293 {
0294 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
0295
0296 if (!ds)
0297 return;
0298
0299 dsa_unregister_switch(ds);
0300
0301 dev_set_drvdata(&mdiodev->dev, NULL);
0302 }
0303
0304 static void mv88e6060_shutdown(struct mdio_device *mdiodev)
0305 {
0306 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
0307
0308 if (!ds)
0309 return;
0310
0311 dsa_switch_shutdown(ds);
0312
0313 dev_set_drvdata(&mdiodev->dev, NULL);
0314 }
0315
0316 static const struct of_device_id mv88e6060_of_match[] = {
0317 {
0318 .compatible = "marvell,mv88e6060",
0319 },
0320 { },
0321 };
0322
0323 static struct mdio_driver mv88e6060_driver = {
0324 .probe = mv88e6060_probe,
0325 .remove = mv88e6060_remove,
0326 .shutdown = mv88e6060_shutdown,
0327 .mdiodrv.driver = {
0328 .name = "mv88e6060",
0329 .of_match_table = mv88e6060_of_match,
0330 },
0331 };
0332
0333 mdio_module_driver(mv88e6060_driver);
0334
0335 MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
0336 MODULE_DESCRIPTION("Driver for Marvell 88E6060 ethernet switch chip");
0337 MODULE_LICENSE("GPL");
0338 MODULE_ALIAS("platform:mv88e6060");