cvmx-helper-sgmii.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  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 "cvmx-config.h"
  33. #include "cvmx-mdio.h"
  34. #include "cvmx-helper.h"
  35. #include "cvmx-helper-board.h"
  36. #include "cvmx-gmxx-defs.h"
  37. #include "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. __cvmx_helper_sgmii_link_set(ipd_port,
  291. __cvmx_helper_sgmii_link_get
  292. (ipd_port));
  293. }
  294. return 0;
  295. }
  296. /**
  297. * Probe a SGMII interface and determine the number of ports
  298. * connected to it. The SGMII interface should still be down after
  299. * this call.
  300. *
  301. * @interface: Interface to probe
  302. *
  303. * Returns Number of ports on the interface. Zero to disable.
  304. */
  305. int __cvmx_helper_sgmii_probe(int interface)
  306. {
  307. union cvmx_gmxx_inf_mode mode;
  308. /*
  309. * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
  310. * interface needs to be enabled before IPD otherwise per port
  311. * backpressure may not work properly
  312. */
  313. mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
  314. mode.s.en = 1;
  315. cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
  316. return 4;
  317. }
  318. /**
  319. * Bringup and enable a SGMII interface. After this call packet
  320. * I/O should be fully functional. This is called with IPD
  321. * enabled but PKO disabled.
  322. *
  323. * @interface: Interface to bring up
  324. *
  325. * Returns Zero on success, negative on failure
  326. */
  327. int __cvmx_helper_sgmii_enable(int interface)
  328. {
  329. int num_ports = cvmx_helper_ports_on_interface(interface);
  330. int index;
  331. __cvmx_helper_sgmii_hardware_init(interface, num_ports);
  332. for (index = 0; index < num_ports; index++) {
  333. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  334. gmxx_prtx_cfg.u64 =
  335. cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  336. gmxx_prtx_cfg.s.en = 1;
  337. cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
  338. gmxx_prtx_cfg.u64);
  339. __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
  340. }
  341. __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
  342. __cvmx_interrupt_gmxx_enable(interface);
  343. return 0;
  344. }
  345. /**
  346. * Return the link state of an IPD/PKO port as returned by
  347. * auto negotiation. The result of this function may not match
  348. * Octeon's link config if auto negotiation has changed since
  349. * the last call to cvmx_helper_link_set().
  350. *
  351. * @ipd_port: IPD/PKO port to query
  352. *
  353. * Returns Link state
  354. */
  355. cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
  356. {
  357. cvmx_helper_link_info_t result;
  358. union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
  359. int interface = cvmx_helper_get_interface_num(ipd_port);
  360. int index = cvmx_helper_get_interface_index_num(ipd_port);
  361. union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
  362. result.u64 = 0;
  363. if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
  364. /* The simulator gives you a simulated 1Gbps full duplex link */
  365. result.s.link_up = 1;
  366. result.s.full_duplex = 1;
  367. result.s.speed = 1000;
  368. return result;
  369. }
  370. pcsx_mrx_control_reg.u64 =
  371. cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  372. if (pcsx_mrx_control_reg.s.loopbck1) {
  373. /* Force 1Gbps full duplex link for internal loopback */
  374. result.s.link_up = 1;
  375. result.s.full_duplex = 1;
  376. result.s.speed = 1000;
  377. return result;
  378. }
  379. pcs_misc_ctl_reg.u64 =
  380. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  381. if (pcs_misc_ctl_reg.s.mode) {
  382. /* 1000BASE-X */
  383. /* FIXME */
  384. } else {
  385. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  386. pcsx_miscx_ctl_reg.u64 =
  387. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  388. if (pcsx_miscx_ctl_reg.s.mac_phy) {
  389. /* PHY Mode */
  390. union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
  391. union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
  392. /*
  393. * Don't bother continuing if the SERTES low
  394. * level link is down
  395. */
  396. pcsx_mrx_status_reg.u64 =
  397. cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
  398. (index, interface));
  399. if (pcsx_mrx_status_reg.s.lnk_st == 0) {
  400. if (__cvmx_helper_sgmii_hardware_init_link
  401. (interface, index) != 0)
  402. return result;
  403. }
  404. /* Read the autoneg results */
  405. pcsx_anx_results_reg.u64 =
  406. cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
  407. (index, interface));
  408. if (pcsx_anx_results_reg.s.an_cpt) {
  409. /*
  410. * Auto negotiation is complete. Set
  411. * status accordingly.
  412. */
  413. result.s.full_duplex =
  414. pcsx_anx_results_reg.s.dup;
  415. result.s.link_up =
  416. pcsx_anx_results_reg.s.link_ok;
  417. switch (pcsx_anx_results_reg.s.spd) {
  418. case 0:
  419. result.s.speed = 10;
  420. break;
  421. case 1:
  422. result.s.speed = 100;
  423. break;
  424. case 2:
  425. result.s.speed = 1000;
  426. break;
  427. default:
  428. result.s.speed = 0;
  429. result.s.link_up = 0;
  430. break;
  431. }
  432. } else {
  433. /*
  434. * Auto negotiation isn't
  435. * complete. Return link down.
  436. */
  437. result.s.speed = 0;
  438. result.s.link_up = 0;
  439. }
  440. } else { /* MAC Mode */
  441. result = __cvmx_helper_board_link_get(ipd_port);
  442. }
  443. }
  444. return result;
  445. }
  446. /**
  447. * Configure an IPD/PKO port for the specified link state. This
  448. * function does not influence auto negotiation at the PHY level.
  449. * The passed link state must always match the link state returned
  450. * by cvmx_helper_link_get(). It is normally best to use
  451. * cvmx_helper_link_autoconf() instead.
  452. *
  453. * @ipd_port: IPD/PKO port to configure
  454. * @link_info: The new link state
  455. *
  456. * Returns Zero on success, negative on failure
  457. */
  458. int __cvmx_helper_sgmii_link_set(int ipd_port,
  459. cvmx_helper_link_info_t link_info)
  460. {
  461. int interface = cvmx_helper_get_interface_num(ipd_port);
  462. int index = cvmx_helper_get_interface_index_num(ipd_port);
  463. __cvmx_helper_sgmii_hardware_init_link(interface, index);
  464. return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
  465. link_info);
  466. }
  467. /**
  468. * Configure a port for internal and/or external loopback. Internal
  469. * loopback causes packets sent by the port to be received by
  470. * Octeon. External loopback causes packets received from the wire to
  471. * sent out again.
  472. *
  473. * @ipd_port: IPD/PKO port to loopback.
  474. * @enable_internal:
  475. * Non zero if you want internal loopback
  476. * @enable_external:
  477. * Non zero if you want external loopback
  478. *
  479. * Returns Zero on success, negative on failure.
  480. */
  481. int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal,
  482. int enable_external)
  483. {
  484. int interface = cvmx_helper_get_interface_num(ipd_port);
  485. int index = cvmx_helper_get_interface_index_num(ipd_port);
  486. union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
  487. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  488. pcsx_mrx_control_reg.u64 =
  489. cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  490. pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
  491. cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  492. pcsx_mrx_control_reg.u64);
  493. pcsx_miscx_ctl_reg.u64 =
  494. cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  495. pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
  496. cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  497. pcsx_miscx_ctl_reg.u64);
  498. __cvmx_helper_sgmii_hardware_init_link(interface, index);
  499. return 0;
  500. }