pcs-lynx.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
  2. /* Copyright 2020 NXP
  3. * Lynx PCS MDIO helpers
  4. */
  5. #include <linux/mdio.h>
  6. #include <linux/phylink.h>
  7. #include <linux/pcs-lynx.h>
  8. #include <linux/property.h>
  9. #define SGMII_CLOCK_PERIOD_NS 8 /* PCS is clocked at 125 MHz */
  10. #define LINK_TIMER_VAL(ns) ((u32)((ns) / SGMII_CLOCK_PERIOD_NS))
  11. #define LINK_TIMER_LO 0x12
  12. #define LINK_TIMER_HI 0x13
  13. #define IF_MODE 0x14
  14. #define IF_MODE_SGMII_EN BIT(0)
  15. #define IF_MODE_USE_SGMII_AN BIT(1)
  16. #define IF_MODE_SPEED(x) (((x) << 2) & GENMASK(3, 2))
  17. #define IF_MODE_SPEED_MSK GENMASK(3, 2)
  18. #define IF_MODE_HALF_DUPLEX BIT(4)
  19. struct lynx_pcs {
  20. struct phylink_pcs pcs;
  21. struct mdio_device *mdio;
  22. };
  23. enum sgmii_speed {
  24. SGMII_SPEED_10 = 0,
  25. SGMII_SPEED_100 = 1,
  26. SGMII_SPEED_1000 = 2,
  27. SGMII_SPEED_2500 = 2,
  28. };
  29. #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
  30. #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs)
  31. static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
  32. struct phylink_link_state *state)
  33. {
  34. struct mii_bus *bus = pcs->bus;
  35. int addr = pcs->addr;
  36. int status, lpa;
  37. status = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_BMSR);
  38. if (status < 0)
  39. return;
  40. state->link = !!(status & MDIO_STAT1_LSTATUS);
  41. state->an_complete = !!(status & MDIO_AN_STAT1_COMPLETE);
  42. if (!state->link || !state->an_complete)
  43. return;
  44. lpa = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_LPA);
  45. if (lpa < 0)
  46. return;
  47. phylink_decode_usxgmii_word(state, lpa);
  48. }
  49. static void lynx_pcs_get_state_2500basex(struct mdio_device *pcs,
  50. struct phylink_link_state *state)
  51. {
  52. int bmsr;
  53. bmsr = mdiodev_read(pcs, MII_BMSR);
  54. if (bmsr < 0) {
  55. state->link = false;
  56. return;
  57. }
  58. state->link = !!(bmsr & BMSR_LSTATUS);
  59. state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
  60. if (!state->link)
  61. return;
  62. state->speed = SPEED_2500;
  63. state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX;
  64. state->duplex = DUPLEX_FULL;
  65. }
  66. static void lynx_pcs_get_state(struct phylink_pcs *pcs,
  67. struct phylink_link_state *state)
  68. {
  69. struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
  70. switch (state->interface) {
  71. case PHY_INTERFACE_MODE_1000BASEX:
  72. case PHY_INTERFACE_MODE_SGMII:
  73. case PHY_INTERFACE_MODE_QSGMII:
  74. phylink_mii_c22_pcs_get_state(lynx->mdio, state);
  75. break;
  76. case PHY_INTERFACE_MODE_2500BASEX:
  77. lynx_pcs_get_state_2500basex(lynx->mdio, state);
  78. break;
  79. case PHY_INTERFACE_MODE_USXGMII:
  80. lynx_pcs_get_state_usxgmii(lynx->mdio, state);
  81. break;
  82. case PHY_INTERFACE_MODE_10GBASER:
  83. phylink_mii_c45_pcs_get_state(lynx->mdio, state);
  84. break;
  85. default:
  86. break;
  87. }
  88. dev_dbg(&lynx->mdio->dev,
  89. "mode=%s/%s/%s link=%u an_complete=%u\n",
  90. phy_modes(state->interface),
  91. phy_speed_to_str(state->speed),
  92. phy_duplex_to_str(state->duplex),
  93. state->link, state->an_complete);
  94. }
  95. static int lynx_pcs_config_giga(struct mdio_device *pcs,
  96. phy_interface_t interface,
  97. const unsigned long *advertising,
  98. unsigned int neg_mode)
  99. {
  100. int link_timer_ns;
  101. u32 link_timer;
  102. u16 if_mode;
  103. int err;
  104. link_timer_ns = phylink_get_link_timer_ns(interface);
  105. if (link_timer_ns > 0) {
  106. link_timer = LINK_TIMER_VAL(link_timer_ns);
  107. mdiodev_write(pcs, LINK_TIMER_LO, link_timer & 0xffff);
  108. mdiodev_write(pcs, LINK_TIMER_HI, link_timer >> 16);
  109. }
  110. if (interface == PHY_INTERFACE_MODE_1000BASEX) {
  111. if_mode = 0;
  112. } else {
  113. /* SGMII and QSGMII */
  114. if_mode = IF_MODE_SGMII_EN;
  115. if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
  116. if_mode |= IF_MODE_USE_SGMII_AN;
  117. }
  118. err = mdiodev_modify(pcs, IF_MODE,
  119. IF_MODE_SGMII_EN | IF_MODE_USE_SGMII_AN,
  120. if_mode);
  121. if (err)
  122. return err;
  123. return phylink_mii_c22_pcs_config(pcs, interface, advertising,
  124. neg_mode);
  125. }
  126. static int lynx_pcs_config_usxgmii(struct mdio_device *pcs,
  127. const unsigned long *advertising,
  128. unsigned int neg_mode)
  129. {
  130. struct mii_bus *bus = pcs->bus;
  131. int addr = pcs->addr;
  132. if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) {
  133. dev_err(&pcs->dev, "USXGMII only supports in-band AN for now\n");
  134. return -EOPNOTSUPP;
  135. }
  136. /* Configure device ability for the USXGMII Replicator */
  137. return mdiobus_c45_write(bus, addr, MDIO_MMD_VEND2, MII_ADVERTISE,
  138. MDIO_USXGMII_10G | MDIO_USXGMII_LINK |
  139. MDIO_USXGMII_FULL_DUPLEX |
  140. ADVERTISE_SGMII | ADVERTISE_LPACK);
  141. }
  142. static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
  143. phy_interface_t ifmode,
  144. const unsigned long *advertising, bool permit)
  145. {
  146. struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
  147. switch (ifmode) {
  148. case PHY_INTERFACE_MODE_1000BASEX:
  149. case PHY_INTERFACE_MODE_SGMII:
  150. case PHY_INTERFACE_MODE_QSGMII:
  151. return lynx_pcs_config_giga(lynx->mdio, ifmode, advertising,
  152. neg_mode);
  153. case PHY_INTERFACE_MODE_2500BASEX:
  154. if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
  155. dev_err(&lynx->mdio->dev,
  156. "AN not supported on 3.125GHz SerDes lane\n");
  157. return -EOPNOTSUPP;
  158. }
  159. break;
  160. case PHY_INTERFACE_MODE_USXGMII:
  161. return lynx_pcs_config_usxgmii(lynx->mdio, advertising,
  162. neg_mode);
  163. case PHY_INTERFACE_MODE_10GBASER:
  164. /* Nothing to do here for 10GBASER */
  165. break;
  166. default:
  167. return -EOPNOTSUPP;
  168. }
  169. return 0;
  170. }
  171. static void lynx_pcs_an_restart(struct phylink_pcs *pcs)
  172. {
  173. struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
  174. phylink_mii_c22_pcs_an_restart(lynx->mdio);
  175. }
  176. static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs,
  177. unsigned int neg_mode,
  178. int speed, int duplex)
  179. {
  180. u16 if_mode = 0, sgmii_speed;
  181. /* The PCS needs to be configured manually only
  182. * when not operating on in-band mode
  183. */
  184. if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
  185. return;
  186. if (duplex == DUPLEX_HALF)
  187. if_mode |= IF_MODE_HALF_DUPLEX;
  188. switch (speed) {
  189. case SPEED_1000:
  190. sgmii_speed = SGMII_SPEED_1000;
  191. break;
  192. case SPEED_100:
  193. sgmii_speed = SGMII_SPEED_100;
  194. break;
  195. case SPEED_10:
  196. sgmii_speed = SGMII_SPEED_10;
  197. break;
  198. case SPEED_UNKNOWN:
  199. /* Silently don't do anything */
  200. return;
  201. default:
  202. dev_err(&pcs->dev, "Invalid PCS speed %d\n", speed);
  203. return;
  204. }
  205. if_mode |= IF_MODE_SPEED(sgmii_speed);
  206. mdiodev_modify(pcs, IF_MODE,
  207. IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
  208. if_mode);
  209. }
  210. /* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane
  211. * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have
  212. * auto-negotiation of any link parameters. Electrically it is compatible with
  213. * a single lane of XAUI.
  214. * The hardware reference manual wants to call this mode SGMII, but it isn't
  215. * really, since the fundamental features of SGMII:
  216. * - Downgrading the link speed by duplicating symbols
  217. * - Auto-negotiation
  218. * are not there.
  219. * The speed is configured at 1000 in the IF_MODE because the clock frequency
  220. * is actually given by a PLL configured in the Reset Configuration Word (RCW).
  221. * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o
  222. * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a
  223. * lower link speed on line side, the system-side interface remains fixed at
  224. * 2500 Mbps and we do rate adaptation through pause frames.
  225. */
  226. static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs,
  227. unsigned int neg_mode,
  228. int speed, int duplex)
  229. {
  230. u16 if_mode = 0;
  231. if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
  232. dev_err(&pcs->dev, "AN not supported for 2500BaseX\n");
  233. return;
  234. }
  235. if (duplex == DUPLEX_HALF)
  236. if_mode |= IF_MODE_HALF_DUPLEX;
  237. if_mode |= IF_MODE_SPEED(SGMII_SPEED_2500);
  238. mdiodev_modify(pcs, IF_MODE,
  239. IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
  240. if_mode);
  241. }
  242. static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
  243. phy_interface_t interface,
  244. int speed, int duplex)
  245. {
  246. struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
  247. switch (interface) {
  248. case PHY_INTERFACE_MODE_SGMII:
  249. case PHY_INTERFACE_MODE_QSGMII:
  250. lynx_pcs_link_up_sgmii(lynx->mdio, neg_mode, speed, duplex);
  251. break;
  252. case PHY_INTERFACE_MODE_2500BASEX:
  253. lynx_pcs_link_up_2500basex(lynx->mdio, neg_mode, speed, duplex);
  254. break;
  255. case PHY_INTERFACE_MODE_USXGMII:
  256. /* At the moment, only in-band AN is supported for USXGMII
  257. * so nothing to do in link_up
  258. */
  259. break;
  260. default:
  261. break;
  262. }
  263. }
  264. static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
  265. .pcs_get_state = lynx_pcs_get_state,
  266. .pcs_config = lynx_pcs_config,
  267. .pcs_an_restart = lynx_pcs_an_restart,
  268. .pcs_link_up = lynx_pcs_link_up,
  269. };
  270. static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio)
  271. {
  272. struct lynx_pcs *lynx;
  273. lynx = kzalloc(sizeof(*lynx), GFP_KERNEL);
  274. if (!lynx)
  275. return ERR_PTR(-ENOMEM);
  276. mdio_device_get(mdio);
  277. lynx->mdio = mdio;
  278. lynx->pcs.ops = &lynx_pcs_phylink_ops;
  279. lynx->pcs.neg_mode = true;
  280. lynx->pcs.poll = true;
  281. return lynx_to_phylink_pcs(lynx);
  282. }
  283. struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr)
  284. {
  285. struct mdio_device *mdio;
  286. struct phylink_pcs *pcs;
  287. mdio = mdio_device_create(bus, addr);
  288. if (IS_ERR(mdio))
  289. return ERR_CAST(mdio);
  290. pcs = lynx_pcs_create(mdio);
  291. /* lynx_create() has taken a refcount on the mdiodev if it was
  292. * successful. If lynx_create() fails, this will free the mdio
  293. * device here. In any case, we don't need to hold our reference
  294. * anymore, and putting it here will allow mdio_device_put() in
  295. * lynx_destroy() to automatically free the mdio device.
  296. */
  297. mdio_device_put(mdio);
  298. return pcs;
  299. }
  300. EXPORT_SYMBOL(lynx_pcs_create_mdiodev);
  301. /*
  302. * lynx_pcs_create_fwnode() creates a lynx PCS instance from the fwnode
  303. * device indicated by node.
  304. *
  305. * Returns:
  306. * -ENODEV if the fwnode is marked unavailable
  307. * -EPROBE_DEFER if we fail to find the device
  308. * -ENOMEM if we fail to allocate memory
  309. * pointer to a phylink_pcs on success
  310. */
  311. struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node)
  312. {
  313. struct mdio_device *mdio;
  314. struct phylink_pcs *pcs;
  315. if (!fwnode_device_is_available(node))
  316. return ERR_PTR(-ENODEV);
  317. mdio = fwnode_mdio_find_device(node);
  318. if (!mdio)
  319. return ERR_PTR(-EPROBE_DEFER);
  320. pcs = lynx_pcs_create(mdio);
  321. /* lynx_create() has taken a refcount on the mdiodev if it was
  322. * successful. If lynx_create() fails, this will free the mdio
  323. * device here. In any case, we don't need to hold our reference
  324. * anymore, and putting it here will allow mdio_device_put() in
  325. * lynx_destroy() to automatically free the mdio device.
  326. */
  327. mdio_device_put(mdio);
  328. return pcs;
  329. }
  330. EXPORT_SYMBOL_GPL(lynx_pcs_create_fwnode);
  331. void lynx_pcs_destroy(struct phylink_pcs *pcs)
  332. {
  333. struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
  334. mdio_device_put(lynx->mdio);
  335. kfree(lynx);
  336. }
  337. EXPORT_SYMBOL(lynx_pcs_destroy);
  338. MODULE_DESCRIPTION("NXP Lynx PCS phylink library");
  339. MODULE_LICENSE("Dual BSD/GPL");