cvmx-helper-sgmii.c 17 KB

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