mv88e61xx.c 15 KB

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