1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips 4 * Copyright (c) 2008-2009 Marvell Semiconductor 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/etherdevice.h> 9 #include <linux/jiffies.h> 10 #include <linux/list.h> 11 #include <linux/module.h> 12 #include <linux/netdevice.h> 13 #include <linux/phy.h> 14 #include <net/dsa.h> 15 #include "mv88e6060.h" 16 17 static int reg_read(struct mv88e6060_priv *priv, int addr, int reg) 18 { 19 return mdiobus_read_nested(priv->bus, priv->sw_addr + addr, reg); 20 } 21 22 static int reg_write(struct mv88e6060_priv *priv, int addr, int reg, u16 val) 23 { 24 return mdiobus_write_nested(priv->bus, priv->sw_addr + addr, reg, val); 25 } 26 27 static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr) 28 { 29 int ret; 30 31 ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID); 32 if (ret >= 0) { 33 if (ret == PORT_SWITCH_ID_6060) 34 return "Marvell 88E6060 (A0)"; 35 if (ret == PORT_SWITCH_ID_6060_R1 || 36 ret == PORT_SWITCH_ID_6060_R2) 37 return "Marvell 88E6060 (B0)"; 38 if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060) 39 return "Marvell 88E6060"; 40 } 41 42 return NULL; 43 } 44 45 static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds, 46 int port) 47 { 48 return DSA_TAG_PROTO_TRAILER; 49 } 50 51 static int mv88e6060_switch_reset(struct mv88e6060_priv *priv) 52 { 53 int i; 54 int ret; 55 unsigned long timeout; 56 57 /* Set all ports to the disabled state. */ 58 for (i = 0; i < MV88E6060_PORTS; i++) { 59 ret = reg_read(priv, REG_PORT(i), PORT_CONTROL); 60 if (ret < 0) 61 return ret; 62 ret = reg_write(priv, REG_PORT(i), PORT_CONTROL, 63 ret & ~PORT_CONTROL_STATE_MASK); 64 if (ret) 65 return ret; 66 } 67 68 /* Wait for transmit queues to drain. */ 69 usleep_range(2000, 4000); 70 71 /* Reset the switch. */ 72 ret = reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL, 73 GLOBAL_ATU_CONTROL_SWRESET | 74 GLOBAL_ATU_CONTROL_LEARNDIS); 75 if (ret) 76 return ret; 77 78 /* Wait up to one second for reset to complete. */ 79 timeout = jiffies + 1 * HZ; 80 while (time_before(jiffies, timeout)) { 81 ret = reg_read(priv, REG_GLOBAL, GLOBAL_STATUS); 82 if (ret < 0) 83 return ret; 84 85 if (ret & GLOBAL_STATUS_INIT_READY) 86 break; 87 88 usleep_range(1000, 2000); 89 } 90 if (time_after(jiffies, timeout)) 91 return -ETIMEDOUT; 92 93 return 0; 94 } 95 96 static int mv88e6060_setup_global(struct mv88e6060_priv *priv) 97 { 98 int ret; 99 100 /* Disable discarding of frames with excessive collisions, 101 * set the maximum frame size to 1536 bytes, and mask all 102 * interrupt sources. 103 */ 104 ret = reg_write(priv, REG_GLOBAL, GLOBAL_CONTROL, 105 GLOBAL_CONTROL_MAX_FRAME_1536); 106 if (ret) 107 return ret; 108 109 /* Disable automatic address learning. 110 */ 111 return reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL, 112 GLOBAL_ATU_CONTROL_LEARNDIS); 113 } 114 115 static int mv88e6060_setup_port(struct mv88e6060_priv *priv, int p) 116 { 117 int addr = REG_PORT(p); 118 int ret; 119 120 /* Do not force flow control, disable Ingress and Egress 121 * Header tagging, disable VLAN tunneling, and set the port 122 * state to Forwarding. Additionally, if this is the CPU 123 * port, enable Ingress and Egress Trailer tagging mode. 124 */ 125 ret = reg_write(priv, addr, PORT_CONTROL, 126 dsa_is_cpu_port(priv->ds, p) ? 127 PORT_CONTROL_TRAILER | 128 PORT_CONTROL_INGRESS_MODE | 129 PORT_CONTROL_STATE_FORWARDING : 130 PORT_CONTROL_STATE_FORWARDING); 131 if (ret) 132 return ret; 133 134 /* Port based VLAN map: give each port its own address 135 * database, allow the CPU port to talk to each of the 'real' 136 * ports, and allow each of the 'real' ports to only talk to 137 * the CPU port. 138 */ 139 ret = reg_write(priv, addr, PORT_VLAN_MAP, 140 ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | 141 (dsa_is_cpu_port(priv->ds, p) ? 142 dsa_user_ports(priv->ds) : 143 BIT(dsa_to_port(priv->ds, p)->cpu_dp->index))); 144 if (ret) 145 return ret; 146 147 /* Port Association Vector: when learning source addresses 148 * of packets, add the address to the address database using 149 * a port bitmap that has only the bit for this port set and 150 * the other bits clear. 151 */ 152 return reg_write(priv, addr, PORT_ASSOC_VECTOR, BIT(p)); 153 } 154 155 static int mv88e6060_setup_addr(struct mv88e6060_priv *priv) 156 { 157 u8 addr[ETH_ALEN]; 158 int ret; 159 u16 val; 160 161 eth_random_addr(addr); 162 163 val = addr[0] << 8 | addr[1]; 164 165 /* The multicast bit is always transmitted as a zero, so the switch uses 166 * bit 8 for "DiffAddr", where 0 means all ports transmit the same SA. 167 */ 168 val &= 0xfeff; 169 170 ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_01, val); 171 if (ret) 172 return ret; 173 174 ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_23, 175 (addr[2] << 8) | addr[3]); 176 if (ret) 177 return ret; 178 179 return reg_write(priv, REG_GLOBAL, GLOBAL_MAC_45, 180 (addr[4] << 8) | addr[5]); 181 } 182 183 static int mv88e6060_setup(struct dsa_switch *ds) 184 { 185 struct mv88e6060_priv *priv = ds->priv; 186 int ret; 187 int i; 188 189 priv->ds = ds; 190 191 ret = mv88e6060_switch_reset(priv); 192 if (ret < 0) 193 return ret; 194 195 /* @@@ initialise atu */ 196 197 ret = mv88e6060_setup_global(priv); 198 if (ret < 0) 199 return ret; 200 201 ret = mv88e6060_setup_addr(priv); 202 if (ret < 0) 203 return ret; 204 205 for (i = 0; i < MV88E6060_PORTS; i++) { 206 ret = mv88e6060_setup_port(priv, i); 207 if (ret < 0) 208 return ret; 209 } 210 211 return 0; 212 } 213 214 static int mv88e6060_port_to_phy_addr(int port) 215 { 216 if (port >= 0 && port < MV88E6060_PORTS) 217 return port; 218 return -1; 219 } 220 221 static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum) 222 { 223 struct mv88e6060_priv *priv = ds->priv; 224 int addr; 225 226 addr = mv88e6060_port_to_phy_addr(port); 227 if (addr == -1) 228 return 0xffff; 229 230 return reg_read(priv, addr, regnum); 231 } 232 233 static int 234 mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) 235 { 236 struct mv88e6060_priv *priv = ds->priv; 237 int addr; 238 239 addr = mv88e6060_port_to_phy_addr(port); 240 if (addr == -1) 241 return 0xffff; 242 243 return reg_write(priv, addr, regnum, val); 244 } 245 246 static const struct dsa_switch_ops mv88e6060_switch_ops = { 247 .get_tag_protocol = mv88e6060_get_tag_protocol, 248 .setup = mv88e6060_setup, 249 .phy_read = mv88e6060_phy_read, 250 .phy_write = mv88e6060_phy_write, 251 }; 252 253 static int mv88e6060_probe(struct mdio_device *mdiodev) 254 { 255 struct device *dev = &mdiodev->dev; 256 struct mv88e6060_priv *priv; 257 struct dsa_switch *ds; 258 const char *name; 259 260 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 261 if (!priv) 262 return -ENOMEM; 263 264 priv->bus = mdiodev->bus; 265 priv->sw_addr = mdiodev->addr; 266 267 name = mv88e6060_get_name(priv->bus, priv->sw_addr); 268 if (!name) 269 return -ENODEV; 270 271 dev_info(dev, "switch %s detected\n", name); 272 273 ds = dsa_switch_alloc(dev, MV88E6060_PORTS); 274 if (!ds) 275 return -ENOMEM; 276 277 ds->priv = priv; 278 ds->dev = dev; 279 ds->ops = &mv88e6060_switch_ops; 280 281 dev_set_drvdata(dev, ds); 282 283 return dsa_register_switch(ds); 284 } 285 286 static void mv88e6060_remove(struct mdio_device *mdiodev) 287 { 288 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 289 290 dsa_unregister_switch(ds); 291 } 292 293 static const struct of_device_id mv88e6060_of_match[] = { 294 { 295 .compatible = "marvell,mv88e6060", 296 }, 297 { /* sentinel */ }, 298 }; 299 300 static struct mdio_driver mv88e6060_driver = { 301 .probe = mv88e6060_probe, 302 .remove = mv88e6060_remove, 303 .mdiodrv.driver = { 304 .name = "mv88e6060", 305 .of_match_table = mv88e6060_of_match, 306 }, 307 }; 308 309 mdio_module_driver(mv88e6060_driver); 310 311 MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 312 MODULE_DESCRIPTION("Driver for Marvell 88E6060 ethernet switch chip"); 313 MODULE_LICENSE("GPL"); 314 MODULE_ALIAS("platform:mv88e6060"); 315