1 /* 2 * (C) Copyright 2009 3 * Marvell Semiconductor <www.marvell.com> 4 * Prafulla Wadaskar <prafulla@marvell.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <netdev.h> 11 #include "mv88e61xx.h" 12 13 /* 14 * Uncomment either of the following line for local debug control; 15 * otherwise global debug control will apply. 16 */ 17 18 /* #undef DEBUG */ 19 /* #define DEBUG */ 20 21 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE 22 /* Chip Address mode 23 * The Switch support two modes of operation 24 * 1. single chip mode and 25 * 2. Multi-chip mode 26 * Refer section 9.2 &9.3 in chip datasheet-02 for more details 27 * 28 * By default single chip mode is configured 29 * multichip mode operation can be configured in board header 30 */ 31 static int mv88e61xx_busychk_multic(char *name, u32 devaddr) 32 { 33 u16 reg = 0; 34 u32 timeout = MV88E61XX_PHY_TIMEOUT; 35 36 /* Poll till SMIBusy bit is clear */ 37 do { 38 miiphy_read(name, devaddr, 0x0, ®); 39 if (timeout-- == 0) { 40 printf("SMI busy timeout\n"); 41 return -1; 42 } 43 } while (reg & (1 << 15)); 44 return 0; 45 } 46 47 static void mv88e61xx_switch_write(char *name, u32 phy_adr, 48 u32 reg_ofs, u16 data) 49 { 50 u16 mii_dev_addr; 51 52 /* command to read PHY dev address */ 53 if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { 54 printf("Error..could not read PHY dev address\n"); 55 return; 56 } 57 mv88e61xx_busychk_multic(name, mii_dev_addr); 58 /* Write data to Switch indirect data register */ 59 miiphy_write(name, mii_dev_addr, 0x1, data); 60 /* Write command to Switch indirect command register (write) */ 61 miiphy_write(name, mii_dev_addr, 0x0, 62 reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 << 63 15)); 64 } 65 66 static void mv88e61xx_switch_read(char *name, u32 phy_adr, 67 u32 reg_ofs, u16 *data) 68 { 69 u16 mii_dev_addr; 70 71 /* command to read PHY dev address */ 72 if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { 73 printf("Error..could not read PHY dev address\n"); 74 return; 75 } 76 mv88e61xx_busychk_multic(name, mii_dev_addr); 77 /* Write command to Switch indirect command register (read) */ 78 miiphy_write(name, mii_dev_addr, 0x0, 79 reg_ofs | (phy_adr << 5) | (1 << 11) | (1 << 12) | (1 << 80 15)); 81 mv88e61xx_busychk_multic(name, mii_dev_addr); 82 /* Read data from Switch indirect data register */ 83 miiphy_read(name, mii_dev_addr, 0x1, data); 84 } 85 #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ 86 87 /* 88 * Convenience macros for switch device/port reads/writes 89 * These macros output valid 'mv88e61xx' U_BOOT_CMDs 90 */ 91 92 #ifndef DEBUG 93 #define WR_SWITCH_REG wr_switch_reg 94 #define RD_SWITCH_REG rd_switch_reg 95 #define WR_SWITCH_PORT_REG(n, p, r, d) \ 96 WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) 97 #define RD_SWITCH_PORT_REG(n, p, r, d) \ 98 RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) 99 #else 100 static void WR_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 data) 101 { 102 printf("mv88e61xx %s dev %02x reg %02x write %04x\n", 103 name, dev_adr, reg_ofs, data); 104 wr_switch_reg(name, dev_adr, reg_ofs, data); 105 } 106 static void RD_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 *data) 107 { 108 rd_switch_reg(name, dev_adr, reg_ofs, data); 109 printf("mv88e61xx %s dev %02x reg %02x read %04x\n", 110 name, dev_adr, reg_ofs, *data); 111 } 112 static void WR_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs, 113 u16 data) 114 { 115 printf("mv88e61xx %s port %02x reg %02x write %04x\n", 116 name, prt_adr, reg_ofs, data); 117 wr_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data); 118 } 119 static void RD_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs, 120 u16 *data) 121 { 122 rd_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data); 123 printf("mv88e61xx %s port %02x reg %02x read %04x\n", 124 name, prt_adr, reg_ofs, *data); 125 } 126 #endif 127 128 /* 129 * Local functions to read/write registers on the switch PHYs. 130 * NOTE! This goes through switch, not direct miiphy, writes and reads! 131 */ 132 133 /* 134 * Make sure SMIBusy bit cleared before another 135 * SMI operation can take place 136 */ 137 static int mv88e61xx_busychk(char *name) 138 { 139 u16 reg = 0; 140 u32 timeout = MV88E61XX_PHY_TIMEOUT; 141 do { 142 rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, 143 MV88E61XX_PHY_CMD, ®); 144 if (timeout-- == 0) { 145 printf("SMI busy timeout\n"); 146 return -1; 147 } 148 } while (reg & 1 << 15); /* busy mask */ 149 return 0; 150 } 151 152 static inline int mv88e61xx_switch_miiphy_write(char *name, u32 phy, 153 u32 reg, u16 data) 154 { 155 /* write switch data reg then cmd reg then check completion */ 156 wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 157 data); 158 wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, 159 (MV88E61XX_PHY_WRITE_CMD | (phy << 5) | reg)); 160 return mv88e61xx_busychk(name); 161 } 162 163 static inline int mv88e61xx_switch_miiphy_read(char *name, u32 phy, 164 u32 reg, u16 *data) 165 { 166 /* write switch cmd reg, check for completion */ 167 wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, 168 (MV88E61XX_PHY_READ_CMD | (phy << 5) | reg)); 169 if (mv88e61xx_busychk(name)) 170 return -1; 171 /* read switch data reg and return success */ 172 rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, data); 173 return 0; 174 } 175 176 /* 177 * Convenience macros for switch PHY reads/writes 178 */ 179 180 #ifndef DEBUG 181 #define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write 182 #define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read 183 #else 184 static inline int WR_SWITCH_PHY_REG(char *name, u32 phy_adr, 185 u32 reg_ofs, u16 data) 186 { 187 int r = mv88e61xx_switch_miiphy_write(name, phy_adr, reg_ofs, data); 188 if (r) 189 printf("** ERROR writing mv88e61xx %s phy %02x reg %02x\n", 190 name, phy_adr, reg_ofs); 191 else 192 printf("mv88e61xx %s phy %02x reg %02x write %04x\n", 193 name, phy_adr, reg_ofs, data); 194 return r; 195 } 196 static inline int RD_SWITCH_PHY_REG(char *name, u32 phy_adr, 197 u32 reg_ofs, u16 *data) 198 { 199 int r = mv88e61xx_switch_miiphy_read(name, phy_adr, reg_ofs, data); 200 if (r) 201 printf("** ERROR reading mv88e61xx %s phy %02x reg %02x\n", 202 name, phy_adr, reg_ofs); 203 else 204 printf("mv88e61xx %s phy %02x reg %02x read %04x\n", 205 name, phy_adr, reg_ofs, *data); 206 return r; 207 } 208 #endif 209 210 static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig) 211 { 212 u32 prt; 213 u16 reg; 214 char *name = swconfig->name; 215 u32 port_mask = swconfig->ports_enabled; 216 217 /* apply internal vlan config */ 218 for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { 219 /* only for enabled ports */ 220 if ((1 << prt) & port_mask) { 221 /* take vlan map from swconfig */ 222 u8 vlanmap = swconfig->vlancfg[prt]; 223 /* remove disabled ports from vlan map */ 224 vlanmap &= swconfig->ports_enabled; 225 /* apply vlan map to port */ 226 RD_SWITCH_PORT_REG(name, prt, 227 MV88E61XX_PRT_VMAP_REG, ®); 228 reg &= ~((1 << MV88E61XX_MAX_PORTS_NUM) - 1); 229 reg |= vlanmap; 230 WR_SWITCH_PORT_REG(name, prt, 231 MV88E61XX_PRT_VMAP_REG, reg); 232 } 233 } 234 } 235 236 /* 237 * Power up the specified port and reset PHY 238 */ 239 static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 phy) 240 { 241 char *name = swconfig->name; 242 243 /* Write Copper Specific control reg1 (0x10) for- 244 * Enable Phy power up 245 * Energy Detect on (sense&Xmit NLP Periodically 246 * reset other settings default 247 */ 248 if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x3360)) 249 return -1; 250 251 /* Write PHY ctrl reg (0x0) to apply 252 * Phy reset (set bit 15 low) 253 * reset other default values 254 */ 255 if (WR_SWITCH_PHY_REG(name, phy, 0x00, 0x9140)) 256 return -1; 257 258 return 0; 259 } 260 261 /* 262 * Default Setup for LED[0]_Control (ref: Table 46 Datasheet-3) 263 * is set to "On-1000Mb/s Link, Off Else" 264 * This function sets it to "On-Link, Blink-Activity, Off-NoLink" 265 * 266 * This is optional settings may be needed on some boards 267 * to setup PHY LEDs default configuration to detect 10/100/1000Mb/s 268 * Link status 269 */ 270 static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 phy) 271 { 272 char *name = swconfig->name; 273 274 if (swconfig->led_init != MV88E61XX_LED_INIT_EN) 275 return 0; 276 277 /* set page address to 3 */ 278 if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0003)) 279 return -1; 280 281 /* 282 * set LED Func Ctrl reg 283 * value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink 284 */ 285 if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x0001)) 286 return -1; 287 288 /* set page address to 0 */ 289 if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0000)) 290 return -1; 291 292 return 0; 293 } 294 295 /* 296 * Reverse Transmit polarity for Media Dependent Interface 297 * Pins (MDIP) bits in Copper Specific Control Register 3 298 * (Page 0, Reg 20 for each phy (except cpu port) 299 * Reference: Section 1.1 Switch datasheet-3 300 * 301 * This is optional settings may be needed on some boards 302 * for PHY<->magnetics h/w tuning 303 */ 304 static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 phy) 305 { 306 char *name = swconfig->name; 307 308 if (swconfig->mdip != MV88E61XX_MDIP_REVERSE) 309 return 0; 310 311 /*Reverse MDIP/N[3:0] bits */ 312 if (WR_SWITCH_PHY_REG(name, phy, 0x14, 0x000f)) 313 return -1; 314 315 return 0; 316 } 317 318 /* 319 * Marvell 88E61XX Switch initialization 320 */ 321 int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) 322 { 323 u32 prt; 324 u16 reg; 325 char *idstr; 326 char *name = swconfig->name; 327 int time; 328 329 if (miiphy_set_current_dev(name)) { 330 printf("%s failed\n", __FUNCTION__); 331 return -1; 332 } 333 334 if (!(swconfig->cpuport & ((1 << 4) | (1 << 5)))) { 335 swconfig->cpuport = (1 << 5); 336 printf("Invalid cpu port config, using default port5\n"); 337 } 338 339 RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, ®); 340 switch (reg &= 0xfff0) { 341 case 0x1610: 342 idstr = "88E6161"; 343 break; 344 case 0x1650: 345 idstr = "88E6165"; 346 break; 347 case 0x1210: 348 idstr = "88E6123"; 349 /* ports 2,3,4 not available */ 350 swconfig->ports_enabled &= 0x023; 351 break; 352 default: 353 /* Could not detect switch id */ 354 idstr = "88E61??"; 355 break; 356 } 357 358 /* be sure all ports are disabled */ 359 for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { 360 RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, ®); 361 reg &= ~0x3; 362 WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg); 363 } 364 365 /* wait 2 ms for queues to drain */ 366 udelay(2000); 367 368 /* reset switch */ 369 RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, ®); 370 reg |= 0x8000; 371 WR_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, reg); 372 373 /* wait up to 1 second for switch reset complete */ 374 for (time = 1000; time; time--) { 375 RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGSR, 376 ®); 377 if ((reg & 0xc800) == 0xc800) 378 break; 379 udelay(1000); 380 } 381 if (!time) 382 return -1; 383 384 /* Port based VLANs configuration */ 385 mv88e61xx_port_vlan_config(swconfig); 386 387 if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) { 388 /* 389 * Enable RGMII delay on Tx and Rx for CPU port 390 * Ref: sec 9.5 of chip datasheet-02 391 */ 392 /*Force port link down */ 393 WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x10); 394 /* configure port RGMII delay */ 395 WR_SWITCH_PORT_REG(name, 4, 396 MV88E61XX_RGMII_TIMECTRL_REG, 0x81e7); 397 RD_SWITCH_PORT_REG(name, 5, 398 MV88E61XX_RGMII_TIMECTRL_REG, ®); 399 WR_SWITCH_PORT_REG(name, 5, 400 MV88E61XX_RGMII_TIMECTRL_REG, reg | 0x18); 401 WR_SWITCH_PORT_REG(name, 4, 402 MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); 403 /* Force port to RGMII FDX 1000Base then up */ 404 WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x1e); 405 WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x3e); 406 } 407 408 for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { 409 410 /* configure port's PHY */ 411 if (!((1 << prt) & swconfig->cpuport)) { 412 /* port 4 has phy 6, not 4 */ 413 int phy = (prt == 4) ? 6 : prt; 414 if (mv88361xx_powerup(swconfig, phy)) 415 return -1; 416 if (mv88361xx_reverse_mdipn(swconfig, phy)) 417 return -1; 418 if (mv88361xx_led_init(swconfig, phy)) 419 return -1; 420 } 421 422 /* set port VID to port+1 except for cpu port */ 423 if (!((1 << prt) & swconfig->cpuport)) { 424 RD_SWITCH_PORT_REG(name, prt, 425 MV88E61XX_PRT_VID_REG, ®); 426 WR_SWITCH_PORT_REG(name, prt, 427 MV88E61XX_PRT_VID_REG, 428 (reg & ~1023) | (prt+1)); 429 } 430 431 /*Program port state */ 432 RD_SWITCH_PORT_REG(name, prt, 433 MV88E61XX_PRT_CTRL_REG, ®); 434 WR_SWITCH_PORT_REG(name, prt, 435 MV88E61XX_PRT_CTRL_REG, 436 reg | (swconfig->portstate & 0x03)); 437 438 } 439 440 printf("%s Initialized on %s\n", idstr, name); 441 return 0; 442 } 443 444 #ifdef CONFIG_MV88E61XX_CMD 445 static int 446 do_switch(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 447 { 448 char *name, *endp; 449 int write = 0; 450 enum { dev, prt, phy } target = dev; 451 u32 addrlo, addrhi, addr; 452 u32 reglo, reghi, reg; 453 u16 data, rdata; 454 455 if (argc < 7) 456 return -1; 457 458 name = argv[1]; 459 460 if (strcmp(argv[2], "phy") == 0) 461 target = phy; 462 else if (strcmp(argv[2], "port") == 0) 463 target = prt; 464 else if (strcmp(argv[2], "dev") != 0) 465 return 1; 466 467 addrlo = simple_strtoul(argv[3], &endp, 16); 468 469 if (!*endp) { 470 addrhi = addrlo; 471 } else { 472 while (*endp < '0' || *endp > '9') 473 endp++; 474 addrhi = simple_strtoul(endp, NULL, 16); 475 } 476 477 reglo = simple_strtoul(argv[5], &endp, 16); 478 if (!*endp) { 479 reghi = reglo; 480 } else { 481 while (*endp < '0' || *endp > '9') 482 endp++; 483 reghi = simple_strtoul(endp, NULL, 16); 484 } 485 486 if (strcmp(argv[6], "write") == 0) 487 write = 1; 488 else if (strcmp(argv[6], "read") != 0) 489 return 1; 490 491 data = simple_strtoul(argv[7], NULL, 16); 492 493 for (addr = addrlo; addr <= addrhi; addr++) { 494 for (reg = reglo; reg <= reghi; reg++) { 495 if (write) { 496 if (target == phy) 497 mv88e61xx_switch_miiphy_write( 498 name, addr, reg, data); 499 else if (target == prt) 500 wr_switch_reg(name, 501 addr+MV88E61XX_PRT_OFST, 502 reg, data); 503 else 504 wr_switch_reg(name, addr, reg, data); 505 } else { 506 if (target == phy) 507 mv88e61xx_switch_miiphy_read( 508 name, addr, reg, &rdata); 509 else if (target == prt) 510 rd_switch_reg(name, 511 addr+MV88E61XX_PRT_OFST, 512 reg, &rdata); 513 else 514 rd_switch_reg(name, addr, reg, &rdata); 515 printf("%s %s %s %02x %s %02x %s %04x\n", 516 argv[0], argv[1], argv[2], addr, 517 argv[4], reg, argv[6], rdata); 518 if (write && argc == 7 && rdata != data) 519 return 1; 520 } 521 } 522 } 523 return 0; 524 } 525 526 U_BOOT_CMD(mv88e61xx, 8, 0, do_switch, 527 "Read or write mv88e61xx switch registers", 528 "<ethdevice> dev|port|phy <addr> reg <reg> write <data>\n" 529 "<ethdevice> dev|port|phy <addr> reg <reg> read [<data>]\n" 530 " - read/write switch device, port or phy at (addr,reg)\n" 531 " addr=0..0x1C for dev, 0..5 for port or phy.\n" 532 " reg=0..0x1F.\n" 533 " data=0..0xFFFF (tested if present against actual read).\n" 534 " All numeric parameters are assumed to be hex.\n" 535 " <addr> and <<reg> arguments can be ranges (x..y)" 536 ); 537 #endif /* CONFIG_MV88E61XX_CMD */ 538