mv88e61xx.c 14 KB

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