cvmx-helper-sgmii.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. /***********************license start***************
  2. * Author: Cavium Networks
  3. *
  4. * Contact: support@caviumnetworks.com
  5. * This file is part of the OCTEON SDK
  6. *
  7. * Copyright (c) 2003-2008 Cavium Networks
  8. *
  9. * This file is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License, Version 2, as
  11. * published by the Free Software Foundation.
  12. *
  13. * This file is distributed in the hope that it will be useful, but
  14. * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
  15. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
  16. * NONINFRINGEMENT. See the GNU General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this file; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. * or visit http://www.gnu.org/licenses/.
  23. *
  24. * This file may also be available under a different license from Cavium.
  25. * Contact Cavium Networks for more information
  26. ***********************license end**************************************/
  27. /*
  28. * Functions for SGMII initialization, configuration,
  29. * and monitoring.
  30. */
  31. #include <asm/octeon/octeon.h>
  32. #include <asm/octeon/cvmx-config.h>
  33. #include <asm/octeon/cvmx-mdio.h>
  34. #include <asm/octeon/cvmx-helper.h>
  35. #include <asm/octeon/cvmx-helper-board.h>
  36. #include <asm/octeon/cvmx-gmxx-defs.h>
  37. #include <asm/octeon/cvmx-pcsx-defs.h>
  38. void __cvmx_interrupt_gmxx_enable(int interface);
  39. void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block);
  40. void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index);
  41. /**
  42. * Perform initialization required only once for an SGMII port.
  43. *
  44. * @interface: Interface to init
  45. * @index: Index of prot on the interface
  46. *
  47. * Returns Zero on success, negative on failure
  48. */
  49. static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
  50. {
  51. const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
  52. union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
  53. union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
  54. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  55. /* Disable GMX */
  56. gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  57. gmxx_prtx_cfg.s.en = 0;
  58. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  59. /*
  60. * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
  61. * appropriate value. 1000BASE-X specifies a 10ms
  62. * interval. SGMII specifies a 1.6ms interval.
  63. */
  64. pcs_misc_ctl_reg.u64 =
  65. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  66. pcsx_linkx_timer_count_reg.u64 =
  67. cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
  68. if (pcs_misc_ctl_reg.s.mode) {
  69. /* 1000BASE-X */
  70. pcsx_linkx_timer_count_reg.s.count =
  71. (10000ull * clock_mhz) >> 10;
  72. } else {
  73. /* SGMII */
  74. pcsx_linkx_timer_count_reg.s.count =
  75. (1600ull * clock_mhz) >> 10;
  76. }
  77. cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
  78. pcsx_linkx_timer_count_reg.u64);
  79. /*
  80. * Write the advertisement register to be used as the
  81. * tx_Config_Reg<D15:D0> of the autonegotiation. In
  82. * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
  83. * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
  84. * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode,
  85. * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
  86. * step can be skipped.
  87. */
  88. if (pcs_misc_ctl_reg.s.mode) {
  89. /* 1000BASE-X */
  90. union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
  91. pcsx_anx_adv_reg.u64 =
  92. cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
  93. pcsx_anx_adv_reg.s.rem_flt = 0;
  94. pcsx_anx_adv_reg.s.pause = 3;
  95. pcsx_anx_adv_reg.s.hfd = 1;
  96. pcsx_anx_adv_reg.s.fd = 1;
  97. cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),
  98. pcsx_anx_adv_reg.u64);
  99. } else {
  100. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  101. pcsx_miscx_ctl_reg.u64 =
  102. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  103. if (pcsx_miscx_ctl_reg.s.mac_phy) {
  104. /* PHY Mode */
  105. union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
  106. pcsx_sgmx_an_adv_reg.u64 =
  107. cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
  108. (index, interface));
  109. pcsx_sgmx_an_adv_reg.s.link = 1;
  110. pcsx_sgmx_an_adv_reg.s.dup = 1;
  111. pcsx_sgmx_an_adv_reg.s.speed = 2;
  112. cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
  113. (index, interface),
  114. pcsx_sgmx_an_adv_reg.u64);
  115. } else {
  116. /* MAC Mode - Nothing to do */
  117. }
  118. }
  119. return 0;
  120. }
  121. /**
  122. * Initialize the SERTES link for the first time or after a loss
  123. * of link.
  124. *
  125. * @interface: Interface to init
  126. * @index: Index of prot on the interface
  127. *
  128. * Returns Zero on success, negative on failure
  129. */
  130. static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
  131. {
  132. union cvmx_pcsx_mrx_control_reg control_reg;
  133. /*
  134. * Take PCS through a reset sequence.
  135. * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
  136. * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
  137. * value of the other PCS*_MR*_CONTROL_REG bits). Read
  138. * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
  139. * zero.
  140. */
  141. control_reg.u64 =
  142. cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  143. if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
  144. control_reg.s.reset = 1;
  145. cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  146. control_reg.u64);
  147. if (CVMX_WAIT_FOR_FIELD64
  148. (CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  149. union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {
  150. cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
  151. "to finish reset\n",
  152. interface, index);
  153. return -1;
  154. }
  155. }
  156. /*
  157. * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
  158. * sgmii negotiation starts.
  159. */
  160. control_reg.s.rst_an = 1;
  161. control_reg.s.an_en = 1;
  162. control_reg.s.pwr_dn = 0;
  163. cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  164. control_reg.u64);
  165. /*
  166. * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
  167. * that sgmii autonegotiation is complete. In MAC mode this
  168. * isn't an ethernet link, but a link between Octeon and the
  169. * PHY.
  170. */
  171. if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
  172. CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
  173. union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
  174. 10000)) {
  175. /* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */
  176. return -1;
  177. }
  178. return 0;
  179. }
  180. /**
  181. * Configure an SGMII link to the specified speed after the SERTES
  182. * link is up.
  183. *
  184. * @interface: Interface to init
  185. * @index: Index of prot on the interface
  186. * @link_info: Link state to configure
  187. *
  188. * Returns Zero on success, negative on failure
  189. */
  190. static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
  191. int index,
  192. cvmx_helper_link_info_t
  193. link_info)
  194. {
  195. int is_enabled;
  196. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  197. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  198. /* Disable GMX before we make any changes. Remember the enable state */
  199. gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  200. is_enabled = gmxx_prtx_cfg.s.en;
  201. gmxx_prtx_cfg.s.en = 0;
  202. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  203. /* Wait for GMX to be idle */
  204. if (CVMX_WAIT_FOR_FIELD64
  205. (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,
  206. rx_idle, ==, 1, 10000)
  207. || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
  208. union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,
  209. 10000)) {
  210. cvmx_dprintf
  211. ("SGMII%d: Timeout waiting for port %d to be idle\n",
  212. interface, index);
  213. return -1;
  214. }
  215. /* Read GMX CFG again to make sure the disable completed */
  216. gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  217. /*
  218. * Get the misc control for PCS. We will need to set the
  219. * duplication amount.
  220. */
  221. pcsx_miscx_ctl_reg.u64 =
  222. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  223. /*
  224. * Use GMXENO to force the link down if the status we get says
  225. * it should be down.
  226. */
  227. pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
  228. /* Only change the duplex setting if the link is up */
  229. if (link_info.s.link_up)
  230. gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
  231. /* Do speed based setting for GMX */
  232. switch (link_info.s.speed) {
  233. case 10:
  234. gmxx_prtx_cfg.s.speed = 0;
  235. gmxx_prtx_cfg.s.speed_msb = 1;
  236. gmxx_prtx_cfg.s.slottime = 0;
  237. /* Setting from GMX-603 */
  238. pcsx_miscx_ctl_reg.s.samp_pt = 25;
  239. cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
  240. cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
  241. break;
  242. case 100:
  243. gmxx_prtx_cfg.s.speed = 0;
  244. gmxx_prtx_cfg.s.speed_msb = 0;
  245. gmxx_prtx_cfg.s.slottime = 0;
  246. pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
  247. cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
  248. cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
  249. break;
  250. case 1000:
  251. gmxx_prtx_cfg.s.speed = 1;
  252. gmxx_prtx_cfg.s.speed_msb = 0;
  253. gmxx_prtx_cfg.s.slottime = 1;
  254. pcsx_miscx_ctl_reg.s.samp_pt = 1;
  255. cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
  256. cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
  257. break;
  258. default:
  259. break;
  260. }
  261. /* Write the new misc control for PCS */
  262. cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  263. pcsx_miscx_ctl_reg.u64);
  264. /* Write the new GMX settings with the port still disabled */
  265. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  266. /* Read GMX CFG again to make sure the config completed */
  267. gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  268. /* Restore the enabled / disabled state */
  269. gmxx_prtx_cfg.s.en = is_enabled;
  270. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  271. return 0;
  272. }
  273. /**
  274. * Bring up the SGMII interface to be ready for packet I/O but
  275. * leave I/O disabled using the GMX override. This function
  276. * follows the bringup documented in 10.6.3 of the manual.
  277. *
  278. * @interface: Interface to bringup
  279. * @num_ports: Number of ports on the interface
  280. *
  281. * Returns Zero on success, negative on failure
  282. */
  283. static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
  284. {
  285. int index;
  286. __cvmx_helper_setup_gmx(interface, num_ports);
  287. for (index = 0; index < num_ports; index++) {
  288. int ipd_port = cvmx_helper_get_ipd_port(interface, index);
  289. __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
  290. /* Linux kernel driver will call ....link_set with the
  291. * proper link state. In the simulator there is no
  292. * link state polling and hence it is set from
  293. * here.
  294. */
  295. if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
  296. __cvmx_helper_sgmii_link_set(ipd_port,
  297. __cvmx_helper_sgmii_link_get(ipd_port));
  298. }
  299. return 0;
  300. }
  301. int __cvmx_helper_sgmii_enumerate(int interface)
  302. {
  303. return 4;
  304. }
  305. /**
  306. * Probe a SGMII interface and determine the number of ports
  307. * connected to it. The SGMII interface should still be down after
  308. * this call.
  309. *
  310. * @interface: Interface to probe
  311. *
  312. * Returns Number of ports on the interface. Zero to disable.
  313. */
  314. int __cvmx_helper_sgmii_probe(int interface)
  315. {
  316. union cvmx_gmxx_inf_mode mode;
  317. /*
  318. * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
  319. * interface needs to be enabled before IPD otherwise per port
  320. * backpressure may not work properly
  321. */
  322. mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
  323. mode.s.en = 1;
  324. cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
  325. return __cvmx_helper_sgmii_enumerate(interface);
  326. }
  327. /**
  328. * Bringup and enable a SGMII interface. After this call packet
  329. * I/O should be fully functional. This is called with IPD
  330. * enabled but PKO disabled.
  331. *
  332. * @interface: Interface to bring up
  333. *
  334. * Returns Zero on success, negative on failure
  335. */
  336. int __cvmx_helper_sgmii_enable(int interface)
  337. {
  338. int num_ports = cvmx_helper_ports_on_interface(interface);
  339. int index;
  340. __cvmx_helper_sgmii_hardware_init(interface, num_ports);
  341. for (index = 0; index < num_ports; index++) {
  342. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  343. gmxx_prtx_cfg.u64 =
  344. cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  345. gmxx_prtx_cfg.s.en = 1;
  346. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
  347. gmxx_prtx_cfg.u64);
  348. __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
  349. }
  350. __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
  351. __cvmx_interrupt_gmxx_enable(interface);
  352. return 0;
  353. }
  354. /**
  355. * Return the link state of an IPD/PKO port as returned by
  356. * auto negotiation. The result of this function may not match
  357. * Octeon's link config if auto negotiation has changed since
  358. * the last call to cvmx_helper_link_set().
  359. *
  360. * @ipd_port: IPD/PKO port to query
  361. *
  362. * Returns Link state
  363. */
  364. cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
  365. {
  366. cvmx_helper_link_info_t result;
  367. union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
  368. int interface = cvmx_helper_get_interface_num(ipd_port);
  369. int index = cvmx_helper_get_interface_index_num(ipd_port);
  370. union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
  371. result.u64 = 0;
  372. if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
  373. /* The simulator gives you a simulated 1Gbps full duplex link */
  374. result.s.link_up = 1;
  375. result.s.full_duplex = 1;
  376. result.s.speed = 1000;
  377. return result;
  378. }
  379. pcsx_mrx_control_reg.u64 =
  380. cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  381. if (pcsx_mrx_control_reg.s.loopbck1) {
  382. /* Force 1Gbps full duplex link for internal loopback */
  383. result.s.link_up = 1;
  384. result.s.full_duplex = 1;
  385. result.s.speed = 1000;
  386. return result;
  387. }
  388. pcs_misc_ctl_reg.u64 =
  389. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  390. if (pcs_misc_ctl_reg.s.mode) {
  391. /* 1000BASE-X */
  392. /* FIXME */
  393. } else {
  394. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  395. pcsx_miscx_ctl_reg.u64 =
  396. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  397. if (pcsx_miscx_ctl_reg.s.mac_phy) {
  398. /* PHY Mode */
  399. union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
  400. union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
  401. /*
  402. * Don't bother continuing if the SERTES low
  403. * level link is down
  404. */
  405. pcsx_mrx_status_reg.u64 =
  406. cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
  407. (index, interface));
  408. if (pcsx_mrx_status_reg.s.lnk_st == 0) {
  409. if (__cvmx_helper_sgmii_hardware_init_link
  410. (interface, index) != 0)
  411. return result;
  412. }
  413. /* Read the autoneg results */
  414. pcsx_anx_results_reg.u64 =
  415. cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
  416. (index, interface));
  417. if (pcsx_anx_results_reg.s.an_cpt) {
  418. /*
  419. * Auto negotiation is complete. Set
  420. * status accordingly.
  421. */
  422. result.s.full_duplex =
  423. pcsx_anx_results_reg.s.dup;
  424. result.s.link_up =
  425. pcsx_anx_results_reg.s.link_ok;
  426. switch (pcsx_anx_results_reg.s.spd) {
  427. case 0:
  428. result.s.speed = 10;
  429. break;
  430. case 1:
  431. result.s.speed = 100;
  432. break;
  433. case 2:
  434. result.s.speed = 1000;
  435. break;
  436. default:
  437. result.s.speed = 0;
  438. result.s.link_up = 0;
  439. break;
  440. }
  441. } else {
  442. /*
  443. * Auto negotiation isn't
  444. * complete. Return link down.
  445. */
  446. result.s.speed = 0;
  447. result.s.link_up = 0;
  448. }
  449. } else { /* MAC Mode */
  450. result = __cvmx_helper_board_link_get(ipd_port);
  451. }
  452. }
  453. return result;
  454. }
  455. /**
  456. * Configure an IPD/PKO port for the specified link state. This
  457. * function does not influence auto negotiation at the PHY level.
  458. * The passed link state must always match the link state returned
  459. * by cvmx_helper_link_get(). It is normally best to use
  460. * cvmx_helper_link_autoconf() instead.
  461. *
  462. * @ipd_port: IPD/PKO port to configure
  463. * @link_info: The new link state
  464. *
  465. * Returns Zero on success, negative on failure
  466. */
  467. int __cvmx_helper_sgmii_link_set(int ipd_port,
  468. cvmx_helper_link_info_t link_info)
  469. {
  470. int interface = cvmx_helper_get_interface_num(ipd_port);
  471. int index = cvmx_helper_get_interface_index_num(ipd_port);
  472. __cvmx_helper_sgmii_hardware_init_link(interface, index);
  473. return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
  474. link_info);
  475. }
  476. /**
  477. * Configure a port for internal and/or external loopback. Internal
  478. * loopback causes packets sent by the port to be received by
  479. * Octeon. External loopback causes packets received from the wire to
  480. * sent out again.
  481. *
  482. * @ipd_port: IPD/PKO port to loopback.
  483. * @enable_internal:
  484. * Non zero if you want internal loopback
  485. * @enable_external:
  486. * Non zero if you want external loopback
  487. *
  488. * Returns Zero on success, negative on failure.
  489. */
  490. int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal,
  491. int enable_external)
  492. {
  493. int interface = cvmx_helper_get_interface_num(ipd_port);
  494. int index = cvmx_helper_get_interface_index_num(ipd_port);
  495. union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
  496. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  497. pcsx_mrx_control_reg.u64 =
  498. cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  499. pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
  500. cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  501. pcsx_mrx_control_reg.u64);
  502. pcsx_miscx_ctl_reg.u64 =
  503. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  504. pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
  505. cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  506. pcsx_miscx_ctl_reg.u64);
  507. __cvmx_helper_sgmii_hardware_init_link(interface, index);
  508. return 0;
  509. }