cvmx-helper-sgmii.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018-2022 Marvell International Ltd.
  4. *
  5. * Functions for SGMII initialization, configuration,
  6. * and monitoring.
  7. */
  8. #include <time.h>
  9. #include <log.h>
  10. #include <linux/delay.h>
  11. #include <mach/cvmx-regs.h>
  12. #include <mach/cvmx-csr.h>
  13. #include <mach/cvmx-bootmem.h>
  14. #include <mach/octeon-model.h>
  15. #include <mach/cvmx-fuse.h>
  16. #include <mach/octeon-feature.h>
  17. #include <mach/cvmx-qlm.h>
  18. #include <mach/octeon_qlm.h>
  19. #include <mach/cvmx-pcie.h>
  20. #include <mach/cvmx-coremask.h>
  21. #include <mach/cvmx-agl-defs.h>
  22. #include <mach/cvmx-bgxx-defs.h>
  23. #include <mach/cvmx-ciu-defs.h>
  24. #include <mach/cvmx-gmxx-defs.h>
  25. #include <mach/cvmx-ipd-defs.h>
  26. #include <mach/cvmx-pcsx-defs.h>
  27. #include <mach/cvmx-pki-defs.h>
  28. #include <mach/cvmx-xcv-defs.h>
  29. #include <mach/cvmx-helper.h>
  30. #include <mach/cvmx-helper-board.h>
  31. #include <mach/cvmx-helper-cfg.h>
  32. /**
  33. * @INTERNAL
  34. * Perform initialization required only once for an SGMII port.
  35. *
  36. * @param interface to init
  37. * @param index Index of prot on the interface
  38. *
  39. * @return Zero on success, negative on failure
  40. */
  41. static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
  42. {
  43. const u64 clock_mhz = 1200; /* todo: fixme */
  44. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  45. union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
  46. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  47. if (!cvmx_helper_is_port_valid(interface, index))
  48. return 0;
  49. /* Disable GMX */
  50. gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
  51. gmxx_prtx_cfg.s.en = 0;
  52. csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  53. /*
  54. * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
  55. * appropriate value. 1000BASE-X specifies a 10ms
  56. * interval. SGMII specifies a 1.6ms interval.
  57. */
  58. pcsx_miscx_ctl_reg.u64 =
  59. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  60. /* Adjust the MAC mode if requested by device tree */
  61. pcsx_miscx_ctl_reg.s.mac_phy =
  62. cvmx_helper_get_mac_phy_mode(interface, index);
  63. pcsx_miscx_ctl_reg.s.mode =
  64. cvmx_helper_get_1000x_mode(interface, index);
  65. csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  66. pcsx_miscx_ctl_reg.u64);
  67. pcsx_linkx_timer_count_reg.u64 =
  68. csr_rd(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
  69. if (pcsx_miscx_ctl_reg.s.mode)
  70. /* 1000BASE-X */
  71. pcsx_linkx_timer_count_reg.s.count =
  72. (10000ull * clock_mhz) >> 10;
  73. else
  74. /* SGMII */
  75. pcsx_linkx_timer_count_reg.s.count =
  76. (1600ull * clock_mhz) >> 10;
  77. csr_wr(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 (pcsx_miscx_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. csr_rd(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. csr_wr(CVMX_PCSX_ANX_ADV_REG(index, interface),
  98. pcsx_anx_adv_reg.u64);
  99. } else {
  100. if (pcsx_miscx_ctl_reg.s.mac_phy) {
  101. /* PHY Mode */
  102. union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
  103. pcsx_sgmx_an_adv_reg.u64 = csr_rd(
  104. CVMX_PCSX_SGMX_AN_ADV_REG(index, interface));
  105. pcsx_sgmx_an_adv_reg.s.dup = 1;
  106. pcsx_sgmx_an_adv_reg.s.speed = 2;
  107. csr_wr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface),
  108. pcsx_sgmx_an_adv_reg.u64);
  109. } else {
  110. /* MAC Mode - Nothing to do */
  111. }
  112. }
  113. return 0;
  114. }
  115. static int __cvmx_helper_need_g15618(void)
  116. {
  117. if (OCTEON_IS_MODEL(OCTEON_CN63XX) ||
  118. OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X) ||
  119. OCTEON_IS_MODEL(OCTEON_CN68XX))
  120. return 1;
  121. else
  122. return 0;
  123. }
  124. /**
  125. * @INTERNAL
  126. * Initialize the SERTES link for the first time or after a loss
  127. * of link.
  128. *
  129. * @param interface to init
  130. * @param index Index of prot on the interface
  131. *
  132. * @return Zero on success, negative on failure
  133. */
  134. static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
  135. {
  136. union cvmx_pcsx_mrx_control_reg control_reg;
  137. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  138. bool phy_mode;
  139. bool an_disable; /** Disable autonegotiation */
  140. bool mode_1000x; /** 1000Base-X mode */
  141. if (!cvmx_helper_is_port_valid(interface, index))
  142. return 0;
  143. /*
  144. * Take PCS through a reset sequence.
  145. * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
  146. * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
  147. * value of the other PCS*_MR*_CONTROL_REG bits). Read
  148. * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
  149. * zero.
  150. */
  151. control_reg.u64 = csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  152. /*
  153. * Errata G-15618 requires disabling PCS soft reset in CN63XX
  154. * pass upto 2.1.
  155. */
  156. if (!__cvmx_helper_need_g15618()) {
  157. control_reg.s.reset = 1;
  158. csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  159. control_reg.u64);
  160. if (CVMX_WAIT_FOR_FIELD64(
  161. CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  162. cvmx_pcsx_mrx_control_reg_t, reset, ==, 0, 10000)) {
  163. debug("SGMII%x: Timeout waiting for port %d to finish reset\n",
  164. interface, index);
  165. return -1;
  166. }
  167. }
  168. /*
  169. * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
  170. * sgmii negotiation starts.
  171. */
  172. phy_mode = cvmx_helper_get_mac_phy_mode(interface, index);
  173. an_disable = (phy_mode ||
  174. !cvmx_helper_get_port_autonegotiation(interface, index));
  175. control_reg.s.an_en = !an_disable;
  176. /* Force a PCS reset by powering down the PCS interface
  177. * This is needed to deal with broken Qualcomm/Atheros PHYs and switches
  178. * which never recover if PCS is not power cycled. The alternative
  179. * is to power cycle or hardware reset the Qualcomm devices whenever
  180. * SGMII is initialized.
  181. *
  182. * This is needed for the QCA8033 PHYs as well as the QCA833X switches
  183. * to work. The QCA8337 switch has additional SGMII problems and is
  184. * best avoided if at all possible. Failure to power cycle PCS prevents
  185. * any traffic from flowing between Octeon and Qualcomm devices if there
  186. * is a warm reset. Even a software reset to the Qualcomm device will
  187. * not work.
  188. *
  189. * Note that this problem has been reported between Qualcomm and other
  190. * vendor's processors as well so this problem is not unique to
  191. * Qualcomm and Octeon.
  192. *
  193. * Power cycling PCS doesn't hurt anything with non-Qualcomm devices
  194. * other than adding a 25ms delay during initialization.
  195. */
  196. control_reg.s.pwr_dn = 1;
  197. csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
  198. csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  199. /* 25ms should be enough, 10ms is too short */
  200. mdelay(25);
  201. control_reg.s.pwr_dn = 0;
  202. csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
  203. /* The Cortina PHY runs in 1000base-X mode */
  204. mode_1000x = cvmx_helper_get_1000x_mode(interface, index);
  205. pcsx_miscx_ctl_reg.u64 =
  206. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  207. pcsx_miscx_ctl_reg.s.mode = mode_1000x;
  208. pcsx_miscx_ctl_reg.s.mac_phy = phy_mode;
  209. csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  210. pcsx_miscx_ctl_reg.u64);
  211. if (an_disable)
  212. /* In PHY mode we can't query the link status so we just
  213. * assume that the link is up.
  214. */
  215. return 0;
  216. /*
  217. * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
  218. * that sgmii autonegotiation is complete. In MAC mode this
  219. * isn't an ethernet link, but a link between Octeon and the
  220. * PHY.
  221. */
  222. if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
  223. union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
  224. 10000)) {
  225. debug("SGMII%x: Port %d link timeout\n", interface, index);
  226. return -1;
  227. }
  228. return 0;
  229. }
  230. /**
  231. * @INTERNAL
  232. * Configure an SGMII link to the specified speed after the SERTES
  233. * link is up.
  234. *
  235. * @param interface to init
  236. * @param index Index of prot on the interface
  237. * @param link_info Link state to configure
  238. *
  239. * @return Zero on success, negative on failure
  240. */
  241. static int
  242. __cvmx_helper_sgmii_hardware_init_link_speed(int interface, int index,
  243. cvmx_helper_link_info_t link_info)
  244. {
  245. int is_enabled;
  246. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  247. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  248. if (!cvmx_helper_is_port_valid(interface, index))
  249. return 0;
  250. /* Disable GMX before we make any changes. Remember the enable state */
  251. gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
  252. is_enabled = gmxx_prtx_cfg.s.en;
  253. gmxx_prtx_cfg.s.en = 0;
  254. csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  255. /* Wait for GMX to be idle */
  256. if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
  257. cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1,
  258. 10000) ||
  259. CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
  260. cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1,
  261. 10000)) {
  262. debug("SGMII%d: Timeout waiting for port %d to be idle\n",
  263. interface, index);
  264. return -1;
  265. }
  266. /* Read GMX CFG again to make sure the disable completed */
  267. gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
  268. /*
  269. * Get the misc control for PCS. We will need to set the
  270. * duplication amount.
  271. */
  272. pcsx_miscx_ctl_reg.u64 =
  273. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  274. /*
  275. * Use GMXENO to force the link down if the status we get says
  276. * it should be down.
  277. */
  278. pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
  279. /* Only change the duplex setting if the link is up */
  280. if (link_info.s.link_up)
  281. gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
  282. /* Do speed based setting for GMX */
  283. switch (link_info.s.speed) {
  284. case 10:
  285. gmxx_prtx_cfg.s.speed = 0;
  286. gmxx_prtx_cfg.s.speed_msb = 1;
  287. gmxx_prtx_cfg.s.slottime = 0;
  288. /* Setting from GMX-603 */
  289. pcsx_miscx_ctl_reg.s.samp_pt = 25;
  290. csr_wr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
  291. csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 0);
  292. break;
  293. case 100:
  294. gmxx_prtx_cfg.s.speed = 0;
  295. gmxx_prtx_cfg.s.speed_msb = 0;
  296. gmxx_prtx_cfg.s.slottime = 0;
  297. pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
  298. csr_wr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
  299. csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 0);
  300. break;
  301. case 1000:
  302. gmxx_prtx_cfg.s.speed = 1;
  303. gmxx_prtx_cfg.s.speed_msb = 0;
  304. gmxx_prtx_cfg.s.slottime = 1;
  305. pcsx_miscx_ctl_reg.s.samp_pt = 1;
  306. csr_wr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
  307. if (gmxx_prtx_cfg.s.duplex)
  308. /* full duplex */
  309. csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 0);
  310. else
  311. /* half duplex */
  312. csr_wr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
  313. break;
  314. default:
  315. break;
  316. }
  317. /* Write the new misc control for PCS */
  318. csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  319. pcsx_miscx_ctl_reg.u64);
  320. /* Write the new GMX settings with the port still disabled */
  321. csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  322. /* Read GMX CFG again to make sure the config completed */
  323. gmxx_prtx_cfg.u64 = csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
  324. /* Restore the enabled / disabled state */
  325. gmxx_prtx_cfg.s.en = is_enabled;
  326. csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  327. return 0;
  328. }
  329. /**
  330. * @INTERNAL
  331. * Bring up the SGMII interface to be ready for packet I/O but
  332. * leave I/O disabled using the GMX override. This function
  333. * follows the bringup documented in 10.6.3 of the manual.
  334. *
  335. * @param interface to bringup
  336. * @param num_ports Number of ports on the interface
  337. *
  338. * @return Zero on success, negative on failure
  339. */
  340. static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
  341. {
  342. int index;
  343. int do_link_set = 1;
  344. /*
  345. * CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis
  346. * be programmed.
  347. */
  348. if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) {
  349. union cvmx_ciu_qlm2 ciu_qlm;
  350. ciu_qlm.u64 = csr_rd(CVMX_CIU_QLM2);
  351. ciu_qlm.s.txbypass = 1;
  352. ciu_qlm.s.txdeemph = 0xf;
  353. ciu_qlm.s.txmargin = 0xd;
  354. csr_wr(CVMX_CIU_QLM2, ciu_qlm.u64);
  355. }
  356. /*
  357. * CN63XX Pass 2.x errata G-15273 requires the QLM De-emphasis
  358. * be programmed when using a 156.25Mhz ref clock.
  359. */
  360. if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_X)) {
  361. /* Read the QLM speed pins */
  362. union cvmx_mio_rst_boot mio_rst_boot;
  363. mio_rst_boot.u64 = csr_rd(CVMX_MIO_RST_BOOT);
  364. if (mio_rst_boot.cn63xx.qlm2_spd == 4) {
  365. union cvmx_ciu_qlm2 ciu_qlm;
  366. ciu_qlm.u64 = csr_rd(CVMX_CIU_QLM2);
  367. ciu_qlm.s.txbypass = 1;
  368. ciu_qlm.s.txdeemph = 0x0;
  369. ciu_qlm.s.txmargin = 0xf;
  370. csr_wr(CVMX_CIU_QLM2, ciu_qlm.u64);
  371. }
  372. }
  373. __cvmx_helper_setup_gmx(interface, num_ports);
  374. for (index = 0; index < num_ports; index++) {
  375. int ipd_port = cvmx_helper_get_ipd_port(interface, index);
  376. if (!cvmx_helper_is_port_valid(interface, index))
  377. continue;
  378. __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
  379. if (do_link_set)
  380. __cvmx_helper_sgmii_link_set(ipd_port,
  381. __cvmx_helper_sgmii_link_get(ipd_port));
  382. }
  383. return 0;
  384. }
  385. int __cvmx_helper_sgmii_enumerate(int xiface)
  386. {
  387. if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
  388. return 2;
  389. if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
  390. struct cvmx_xiface xi =
  391. cvmx_helper_xiface_to_node_interface(xiface);
  392. enum cvmx_qlm_mode qlm_mode =
  393. cvmx_qlm_get_dlm_mode(0, xi.interface);
  394. if (qlm_mode == CVMX_QLM_MODE_SGMII)
  395. return 1;
  396. else if (qlm_mode == CVMX_QLM_MODE_QSGMII)
  397. return 4;
  398. return 0;
  399. }
  400. return 4;
  401. }
  402. /**
  403. * @INTERNAL
  404. * Probe a SGMII interface and determine the number of ports
  405. * connected to it. The SGMII interface should still be down after
  406. * this call.
  407. *
  408. * @param xiface Interface to probe
  409. *
  410. * @return Number of ports on the interface. Zero to disable.
  411. */
  412. int __cvmx_helper_sgmii_probe(int xiface)
  413. {
  414. struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
  415. int interface = xi.interface;
  416. union cvmx_gmxx_inf_mode mode;
  417. int ports;
  418. /*
  419. * Check if QLM is configured correct for SGMII, verify the
  420. * speed as well as mode.
  421. */
  422. if (OCTEON_IS_OCTEON2()) {
  423. int qlm = cvmx_qlm_interface(xiface);
  424. if (cvmx_qlm_get_mode(qlm) != CVMX_QLM_MODE_SGMII)
  425. return 0;
  426. }
  427. /* Do not enable the interface if is not in SGMII mode */
  428. ports = __cvmx_helper_sgmii_enumerate(xiface);
  429. if (ports <= 0)
  430. return 0;
  431. /*
  432. * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
  433. * interface needs to be enabled before IPD otherwise per port
  434. * backpressure may not work properly.
  435. */
  436. mode.u64 = csr_rd(CVMX_GMXX_INF_MODE(interface));
  437. mode.s.en = 1;
  438. csr_wr(CVMX_GMXX_INF_MODE(interface), mode.u64);
  439. return ports;
  440. }
  441. /**
  442. * @INTERNAL
  443. * Bringup and enable a SGMII interface. After this call packet
  444. * I/O should be fully functional. This is called with IPD
  445. * enabled but PKO disabled.
  446. *
  447. * @param xiface Interface to bring up
  448. *
  449. * @return Zero on success, negative on failure
  450. */
  451. int __cvmx_helper_sgmii_enable(int xiface)
  452. {
  453. int num_ports = cvmx_helper_ports_on_interface(xiface);
  454. struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
  455. int interface = xi.interface;
  456. int index;
  457. /* Setup PKND and BPID */
  458. if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
  459. for (index = 0; index < num_ports; index++) {
  460. union cvmx_gmxx_bpid_msk bpid_msk;
  461. union cvmx_gmxx_bpid_mapx bpid_map;
  462. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  463. if (!cvmx_helper_is_port_valid(interface, index))
  464. continue;
  465. /* Setup PKIND */
  466. gmxx_prtx_cfg.u64 =
  467. csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
  468. gmxx_prtx_cfg.s.pknd =
  469. cvmx_helper_get_pknd(interface, index);
  470. csr_wr(CVMX_GMXX_PRTX_CFG(index, interface),
  471. gmxx_prtx_cfg.u64);
  472. /* Setup BPID */
  473. bpid_map.u64 =
  474. csr_rd(CVMX_GMXX_BPID_MAPX(index, interface));
  475. bpid_map.s.val = 1;
  476. bpid_map.s.bpid =
  477. cvmx_helper_get_bpid(interface, index);
  478. csr_wr(CVMX_GMXX_BPID_MAPX(index, interface),
  479. bpid_map.u64);
  480. bpid_msk.u64 = csr_rd(CVMX_GMXX_BPID_MSK(interface));
  481. bpid_msk.s.msk_or |= (1 << index);
  482. bpid_msk.s.msk_and &= ~(1 << index);
  483. csr_wr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64);
  484. }
  485. }
  486. __cvmx_helper_sgmii_hardware_init(interface, num_ports);
  487. /* CN68XX adds the padding and FCS in PKO, not GMX */
  488. if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
  489. union cvmx_gmxx_txx_append gmxx_txx_append_cfg;
  490. for (index = 0; index < num_ports; index++) {
  491. if (!cvmx_helper_is_port_valid(interface, index))
  492. continue;
  493. gmxx_txx_append_cfg.u64 =
  494. csr_rd(CVMX_GMXX_TXX_APPEND(index, interface));
  495. gmxx_txx_append_cfg.s.fcs = 0;
  496. gmxx_txx_append_cfg.s.pad = 0;
  497. csr_wr(CVMX_GMXX_TXX_APPEND(index, interface),
  498. gmxx_txx_append_cfg.u64);
  499. }
  500. }
  501. /* Enable running disparity check for QSGMII interface */
  502. if (OCTEON_IS_MODEL(OCTEON_CN70XX) && num_ports > 1) {
  503. union cvmx_gmxx_qsgmii_ctl qsgmii_ctl;
  504. qsgmii_ctl.u64 = 0;
  505. qsgmii_ctl.s.disparity = 1;
  506. csr_wr(CVMX_GMXX_QSGMII_CTL(interface), qsgmii_ctl.u64);
  507. }
  508. for (index = 0; index < num_ports; index++) {
  509. union cvmx_gmxx_txx_append append_cfg;
  510. union cvmx_gmxx_txx_sgmii_ctl sgmii_ctl;
  511. union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  512. if (!cvmx_helper_is_port_valid(interface, index))
  513. continue;
  514. /*
  515. * Clear the align bit if preamble is set to attain
  516. * maximum tx rate.
  517. */
  518. append_cfg.u64 = csr_rd(CVMX_GMXX_TXX_APPEND(index, interface));
  519. sgmii_ctl.u64 =
  520. csr_rd(CVMX_GMXX_TXX_SGMII_CTL(index, interface));
  521. sgmii_ctl.s.align = append_cfg.s.preamble ? 0 : 1;
  522. csr_wr(CVMX_GMXX_TXX_SGMII_CTL(index, interface),
  523. sgmii_ctl.u64);
  524. gmxx_prtx_cfg.u64 =
  525. csr_rd(CVMX_GMXX_PRTX_CFG(index, interface));
  526. gmxx_prtx_cfg.s.en = 1;
  527. csr_wr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  528. }
  529. return 0;
  530. }
  531. /**
  532. * @INTERNAL
  533. * Return the link state of an IPD/PKO port as returned by
  534. * auto negotiation. The result of this function may not match
  535. * Octeon's link config if auto negotiation has changed since
  536. * the last call to cvmx_helper_link_set().
  537. *
  538. * @param ipd_port IPD/PKO port to query
  539. *
  540. * @return Link state
  541. */
  542. cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
  543. {
  544. cvmx_helper_link_info_t result;
  545. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  546. int interface = cvmx_helper_get_interface_num(ipd_port);
  547. int index = cvmx_helper_get_interface_index_num(ipd_port);
  548. union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
  549. int speed = 1000;
  550. int qlm;
  551. result.u64 = 0;
  552. if (!cvmx_helper_is_port_valid(interface, index))
  553. return result;
  554. if (OCTEON_IS_MODEL(OCTEON_CN66XX)) {
  555. union cvmx_gmxx_inf_mode inf_mode;
  556. inf_mode.u64 = csr_rd(CVMX_GMXX_INF_MODE(interface));
  557. if (inf_mode.s.rate & (1 << index))
  558. speed = 2500;
  559. else
  560. speed = 1000;
  561. } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
  562. qlm = cvmx_qlm_interface(interface);
  563. speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10;
  564. } else if (OCTEON_IS_MODEL(OCTEON_CNF71XX)) {
  565. speed = cvmx_qlm_get_gbaud_mhz(0) * 8 / 10;
  566. } else if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
  567. speed = cvmx_qlm_get_gbaud_mhz(0) * 8 / 10;
  568. if (cvmx_qlm_get_dlm_mode(0, interface) == CVMX_QLM_MODE_SGMII)
  569. speed >>= 1;
  570. else
  571. speed >>= 2;
  572. }
  573. pcsx_mrx_control_reg.u64 =
  574. csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  575. if (pcsx_mrx_control_reg.s.loopbck1) {
  576. /* Force 1Gbps full duplex link for internal loopback */
  577. result.s.link_up = 1;
  578. result.s.full_duplex = 1;
  579. result.s.speed = speed;
  580. return result;
  581. }
  582. pcsx_miscx_ctl_reg.u64 =
  583. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  584. if (pcsx_miscx_ctl_reg.s.mac_phy ||
  585. cvmx_helper_get_port_force_link_up(interface, index)) {
  586. /* PHY Mode */
  587. /* Note that this also works for 1000base-X mode */
  588. result.s.speed = speed;
  589. result.s.full_duplex = 1;
  590. result.s.link_up = 1;
  591. return result;
  592. }
  593. /* MAC Mode */
  594. return __cvmx_helper_board_link_get(ipd_port);
  595. }
  596. /**
  597. * @INTERNAL
  598. * Configure an IPD/PKO port for the specified link state. This
  599. * function does not influence auto negotiation at the PHY level.
  600. * The passed link state must always match the link state returned
  601. * by cvmx_helper_link_get(). It is normally best to use
  602. * cvmx_helper_link_autoconf() instead.
  603. *
  604. * @param ipd_port IPD/PKO port to configure
  605. * @param link_info The new link state
  606. *
  607. * @return Zero on success, negative on failure
  608. */
  609. int __cvmx_helper_sgmii_link_set(int ipd_port,
  610. cvmx_helper_link_info_t link_info)
  611. {
  612. union cvmx_pcsx_mrx_control_reg control_reg;
  613. int interface = cvmx_helper_get_interface_num(ipd_port);
  614. int index = cvmx_helper_get_interface_index_num(ipd_port);
  615. if (!cvmx_helper_is_port_valid(interface, index))
  616. return 0;
  617. /* For some devices, i.e. the Qualcomm QCA8337 switch we need to power
  618. * down the PCS interface when the link goes down and power it back
  619. * up when the link returns.
  620. */
  621. if (link_info.s.link_up || !__cvmx_helper_need_g15618()) {
  622. __cvmx_helper_sgmii_hardware_init_link(interface, index);
  623. } else {
  624. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  625. pcsx_miscx_ctl_reg.u64 =
  626. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  627. /* Disable autonegotiation when MAC mode is enabled or
  628. * autonegotiation is disabled.
  629. */
  630. control_reg.u64 =
  631. csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  632. if (pcsx_miscx_ctl_reg.s.mac_phy == 0 ||
  633. !cvmx_helper_get_port_autonegotiation(interface, index)) {
  634. control_reg.s.an_en = 0;
  635. control_reg.s.spdmsb = 1;
  636. control_reg.s.spdlsb = 0;
  637. control_reg.s.dup = 1;
  638. }
  639. csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  640. control_reg.u64);
  641. csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  642. /*
  643. * Use GMXENO to force the link down it will get
  644. * reenabled later...
  645. */
  646. pcsx_miscx_ctl_reg.s.gmxeno = 1;
  647. csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  648. pcsx_miscx_ctl_reg.u64);
  649. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  650. return 0;
  651. }
  652. return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
  653. link_info);
  654. }
  655. /**
  656. * @INTERNAL
  657. * Configure a port for internal and/or external loopback. Internal loopback
  658. * causes packets sent by the port to be received by Octeon. External loopback
  659. * causes packets received from the wire to sent out again.
  660. *
  661. * @param ipd_port IPD/PKO port to loopback.
  662. * @param enable_internal
  663. * Non zero if you want internal loopback
  664. * @param enable_external
  665. * Non zero if you want external loopback
  666. *
  667. * @return Zero on success, negative on failure.
  668. */
  669. int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal,
  670. int enable_external)
  671. {
  672. int interface = cvmx_helper_get_interface_num(ipd_port);
  673. int index = cvmx_helper_get_interface_index_num(ipd_port);
  674. union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
  675. union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
  676. if (!cvmx_helper_is_port_valid(interface, index))
  677. return 0;
  678. pcsx_mrx_control_reg.u64 =
  679. csr_rd(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
  680. pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
  681. csr_wr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
  682. pcsx_mrx_control_reg.u64);
  683. pcsx_miscx_ctl_reg.u64 =
  684. csr_rd(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  685. pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
  686. csr_wr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
  687. pcsx_miscx_ctl_reg.u64);
  688. __cvmx_helper_sgmii_hardware_init_link(interface, index);
  689. return 0;
  690. }