cvi_eth_phy.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
  3. */
  4. #include <rtthread.h>
  5. #include "cvi_eth_phy.h"
  6. #define CSI_ETH_AUTONEG_DISABLE (0) ///< Disable auto-negotiation
  7. #define CSI_ETH_AUTONEG_ENABLE (1) ///< Enable auto-negotiation
  8. #define CONFIG_ETH_PHY_NUM 2
  9. eth_phy_priv_t phy_priv_list[CONFIG_ETH_PHY_NUM];
  10. extern eth_phy_dev_t cv181x_device;
  11. /* registered phy devices */
  12. static eth_phy_dev_t *const eth_phy_devices[] = {
  13. &cv181x_device,
  14. NULL /* Must be the last item */
  15. };
  16. int32_t eth_phy_read(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
  17. {
  18. RT_ASSERT(priv);
  19. RT_ASSERT(priv->phy_read);
  20. return priv->phy_read(phy_addr, reg_addr, data);
  21. }
  22. int32_t eth_phy_write(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
  23. {
  24. RT_ASSERT(priv);
  25. RT_ASSERT(priv->phy_write);
  26. return priv->phy_write(phy_addr, reg_addr, data);
  27. }
  28. static eth_phy_dev_t *eth_get_phy_device(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t phy_id)
  29. {
  30. eth_phy_dev_t *p = eth_phy_devices[0];
  31. int32_t i = 0;
  32. while (p != NULL)
  33. {
  34. if ((p->phy_id & p->mask) == (phy_id & p->mask))
  35. {
  36. p->phy_addr = phy_addr;
  37. p->advertising = p->supported = p->features;
  38. return p;
  39. }
  40. i ++;
  41. p = eth_phy_devices[i];
  42. }
  43. return NULL;
  44. }
  45. static int32_t eth_read_phy_id(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t *phy_id)
  46. {
  47. int32_t ret;
  48. uint16_t data;
  49. uint32_t id;
  50. ret = eth_phy_read(priv, phy_addr, CVI_MII_PHYSID1, &data);
  51. if (ret != 0)
  52. {
  53. return ret;
  54. }
  55. id = data;
  56. id = (id & 0xffff) << 16;
  57. ret = eth_phy_read(priv, phy_addr, CVI_MII_PHYSID2, &data);
  58. if (ret != 0)
  59. {
  60. return ret;
  61. }
  62. id |= (data & 0xffff);
  63. if (phy_id != NULL)
  64. {
  65. *phy_id = id;
  66. }
  67. return 0;
  68. }
  69. static eth_phy_dev_t * eth_get_phy_by_mask(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface)
  70. {
  71. uint32_t phy_id = 0xffffffff;
  72. while (phy_mask)
  73. {
  74. int32_t addr = ffs(phy_mask) - 1;
  75. int32_t r = eth_read_phy_id(priv, addr, &phy_id);
  76. /* If the PHY ID is mostly f's, we didn't find anything */
  77. if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff)
  78. return eth_get_phy_device(priv, addr, phy_id);
  79. phy_mask &= ~(1 << addr);
  80. }
  81. return NULL;
  82. }
  83. static void eth_config(void)
  84. {
  85. unsigned int val;
  86. val = mmio_read_32(ETH_PHY_BASE) & ETH_PHY_INIT_MASK;
  87. mmio_write_32(ETH_PHY_BASE, (val | ETH_PHY_SHUTDOWN) & ETH_PHY_RESET);
  88. rt_thread_mdelay(1);
  89. mmio_write_32(ETH_PHY_BASE, val & ETH_PHY_POWERUP & ETH_PHY_RESET);
  90. rt_thread_mdelay(20);
  91. mmio_write_32(ETH_PHY_BASE, (val & ETH_PHY_POWERUP) | ETH_PHY_RESET_N);
  92. rt_thread_mdelay(1);
  93. }
  94. static eth_phy_dev_t *eth_connect_phy(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface)
  95. {
  96. int32_t i;
  97. eth_phy_dev_t *phydev = NULL;
  98. /* config eth internal phy on ASIC board */
  99. eth_config();
  100. #ifdef CONFIG_PHY_ADDR
  101. phy_mask = 1 << CONFIG_PHY_ADDR;
  102. #endif
  103. for (i = 0; i < 5; i++)
  104. {
  105. phydev = eth_get_phy_by_mask(priv, phy_mask, interface);
  106. if (phydev)
  107. return phydev;
  108. }
  109. rt_kprintf("\n PHY: ");
  110. while (phy_mask)
  111. {
  112. int32_t addr = ffs(phy_mask) - 1;
  113. rt_kprintf("%d ", addr);
  114. phy_mask &= ~(1 << addr);
  115. }
  116. rt_kprintf("not found\n");
  117. return NULL;
  118. }
  119. int32_t eth_phy_reset(eth_phy_handle_t handle)
  120. {
  121. RT_ASSERT(handle);
  122. eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
  123. RT_ASSERT(dev->priv);
  124. uint16_t data;
  125. int32_t ret;
  126. int32_t timeout = 600; /* in ms */
  127. eth_phy_priv_t *priv = dev->priv;
  128. uint32_t phy_addr = dev->phy_addr;
  129. /* Soft reset */
  130. ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
  131. if (ret != 0)
  132. {
  133. rt_kprintf("eth phy read failed\n");
  134. return ret;
  135. }
  136. ret = eth_phy_write(priv, phy_addr, CVI_MII_BMCR, data | CVI_BMCR_RESET);
  137. if (ret != 0)
  138. {
  139. rt_kprintf("eth phy write failed\n");
  140. return ret;
  141. }
  142. #ifdef CONFIG_PHY_RESET_DELAY
  143. rt_hw_us_delay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
  144. #endif
  145. /*
  146. * Wait up to 0.6s for the reset sequence to finish. According to
  147. * IEEE 802.3, Section 2, Subsection 22.2.4.1.1 a PHY reset may take
  148. * up to 0.5 s.
  149. */
  150. ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
  151. while ((data & CVI_BMCR_RESET) && timeout--)
  152. {
  153. ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
  154. if (ret != 0) {
  155. return ret;
  156. }
  157. rt_thread_mdelay(1);
  158. }
  159. if (data & CVI_BMCR_RESET)
  160. {
  161. rt_kprintf("eth phy reset timed out\n");
  162. return -1;
  163. }
  164. return 0;
  165. }
  166. int32_t eth_phy_config(eth_phy_handle_t handle)
  167. {
  168. RT_ASSERT(handle);
  169. eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
  170. if (dev->config)
  171. {
  172. return dev->config(handle);
  173. }
  174. return 0;
  175. }
  176. int32_t eth_phy_start(eth_phy_handle_t handle)
  177. {
  178. RT_ASSERT(handle);
  179. eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
  180. if (dev->start)
  181. {
  182. return dev->start(handle);
  183. }
  184. return 0;
  185. }
  186. int32_t eth_phy_stop(eth_phy_handle_t handle)
  187. {
  188. RT_ASSERT(handle);
  189. eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
  190. if (dev->start) {
  191. return dev->stop(handle);
  192. }
  193. return 0;
  194. }
  195. int32_t cvi_eth_phy_power_control(eth_phy_handle_t handle, eth_power_state_t state)
  196. {
  197. if (state == CSI_ETH_POWER_FULL)
  198. {
  199. return eth_phy_start(handle);
  200. }
  201. else if (state == CSI_ETH_POWER_OFF)
  202. {
  203. return eth_phy_stop(handle);
  204. }
  205. return 0;
  206. }
  207. int32_t genphy_update_link(eth_phy_dev_t *phy_dev)
  208. {
  209. uint8_t phy_addr = phy_dev->phy_addr;
  210. uint16_t mii_reg;
  211. int32_t ret;
  212. /*
  213. * Wait if the link is up, and autonegotiation is in progress
  214. * (ie - we're capable and it's not done)
  215. */
  216. ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
  217. if (ret != 0) {
  218. return ret;
  219. }
  220. /*
  221. * If we already saw the link up, and it hasn't gone down, then
  222. * we don't need to wait for autoneg again
  223. */
  224. if (phy_dev->link_state && mii_reg & CVI_BMSR_LSTATUS)
  225. return 0;
  226. if ((phy_dev->priv->link_info.autoneg == CSI_ETH_AUTONEG_ENABLE) &&
  227. !(mii_reg & CVI_BMSR_ANEGCOMPLETE)) {
  228. int i = 0;
  229. rt_kprintf("%s waiting for PHY auto negotiation to complete...\n",
  230. phy_dev->name);
  231. while (!(mii_reg & CVI_BMSR_ANEGCOMPLETE)) {
  232. /*
  233. * Timeout reached ?
  234. */
  235. if (i > CVI_PHY_ANEG_TIMEOUT) {
  236. rt_kprintf("TIMEOUT!\n");
  237. phy_dev->link_state = ETH_LINK_DOWN;
  238. return -1;
  239. }
  240. // if ((i++ % 1000) == 0)
  241. // rt_kprintf(".");
  242. i ++;
  243. rt_hw_us_delay(1000); /* 1 ms */
  244. ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
  245. if (ret != 0) {
  246. return ret;
  247. }
  248. }
  249. rt_kprintf("auto negotiation Done!\n");
  250. phy_dev->link_state = ETH_LINK_UP;
  251. } else {
  252. /* Read the link a second time to clear the latched state */
  253. ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
  254. if (ret != 0) {
  255. return ret;
  256. }
  257. if (mii_reg & CVI_BMSR_LSTATUS)
  258. phy_dev->link_state = ETH_LINK_UP;
  259. else
  260. phy_dev->link_state = ETH_LINK_DOWN;
  261. }
  262. return 0;
  263. }
  264. int32_t eth_phy_update_link(eth_phy_handle_t handle)
  265. {
  266. RT_ASSERT(handle);
  267. eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
  268. if (dev->update_link) {
  269. return dev->update_link(handle);
  270. } else {
  271. return genphy_update_link(dev);
  272. }
  273. }
  274. static int32_t genphy_config_advert(eth_phy_dev_t *phy_dev)
  275. {
  276. RT_ASSERT(phy_dev->priv);
  277. eth_phy_priv_t *priv = phy_dev->priv;
  278. uint8_t phy_addr = phy_dev->phy_addr;
  279. uint32_t advertise;
  280. uint16_t oldadv, adv, bmsr;
  281. int32_t changed = 0;
  282. int32_t ret;
  283. /* Only allow advertising what this PHY supports */
  284. phy_dev->advertising &= phy_dev->supported;
  285. advertise = phy_dev->advertising;
  286. /* Setup standard advertisement */
  287. ret = eth_phy_read(priv, phy_addr, CVI_MII_ADVERTISE, &adv);
  288. if (ret != 0) {
  289. return ret;
  290. }
  291. oldadv = adv;
  292. if (adv < 0)
  293. return adv;
  294. adv &= ~(CVI_ADVERTISE_ALL | CVI_ADVERTISE_100BASE4 | CVI_ADVERTISE_PAUSE_CAP |
  295. CVI_ADVERTISE_PAUSE_ASYM);
  296. if (advertise & CVI_ADVERTISED_10baseT_Half)
  297. adv |= CVI_ADVERTISE_10HALF;
  298. if (advertise & CVI_ADVERTISED_10baseT_Full)
  299. adv |= CVI_ADVERTISE_10FULL;
  300. if (advertise & CVI_ADVERTISED_100baseT_Half)
  301. adv |= CVI_ADVERTISE_100HALF;
  302. if (advertise & CVI_ADVERTISED_100baseT_Full)
  303. adv |= CVI_ADVERTISE_100FULL;
  304. if (advertise & CVI_ADVERTISED_Pause)
  305. adv |= CVI_ADVERTISE_PAUSE_CAP;
  306. if (advertise & CVI_ADVERTISED_Asym_Pause)
  307. adv |= CVI_ADVERTISE_PAUSE_ASYM;
  308. if (advertise & CVI_ADVERTISED_1000baseX_Half)
  309. adv |= CVI_ADVERTISE_1000XHALF;
  310. if (advertise & CVI_ADVERTISED_1000baseX_Full)
  311. adv |= CVI_ADVERTISE_1000XFULL;
  312. if (adv != oldadv) {
  313. ret = eth_phy_write(priv, phy_addr, CVI_MII_ADVERTISE, adv);
  314. if (ret != 0) {
  315. return ret;
  316. }
  317. changed = 1;
  318. }
  319. ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &bmsr);
  320. if (ret != 0 || bmsr < 0) {
  321. return ret;
  322. }
  323. /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
  324. * 1000Mbits/sec capable PHYs shall have the CVI_BMSR_ESTATEN bit set to a
  325. * logical 1.
  326. */
  327. if (!(bmsr & CVI_BMSR_ESTATEN))
  328. return changed;
  329. /* Configure gigabit if it's supported */
  330. ret = eth_phy_read(priv, phy_addr, CVI_MII_CTRL1000, &adv);
  331. if (ret != 0 || adv < 0) {
  332. return ret;
  333. }
  334. oldadv = adv;
  335. adv &= ~(CVI_ADVERTISE_1000FULL | CVI_ADVERTISE_1000HALF);
  336. if (phy_dev->supported & (CVI_SUPPORTED_1000baseT_Half |
  337. CVI_SUPPORTED_1000baseT_Full)) {
  338. if (advertise & CVI_SUPPORTED_1000baseT_Half)
  339. adv |= CVI_ADVERTISE_1000HALF;
  340. if (advertise & CVI_SUPPORTED_1000baseT_Full)
  341. adv |= CVI_ADVERTISE_1000FULL;
  342. }
  343. if (adv != oldadv)
  344. changed = 1;
  345. ret = eth_phy_write(priv, phy_addr, CVI_MII_CTRL1000, adv);
  346. if (ret != 0) {
  347. return ret;
  348. }
  349. return changed;
  350. }
  351. static int32_t genphy_setup_forced(eth_phy_dev_t *phy_dev)
  352. {
  353. RT_ASSERT(phy_dev->priv);
  354. eth_phy_priv_t *priv = phy_dev->priv;
  355. uint8_t phy_addr = phy_dev->phy_addr;
  356. int32_t ctl = CVI_BMCR_ANRESTART;
  357. int32_t ret;
  358. if (CSI_ETH_SPEED_1G == priv->link_info.speed)
  359. ctl |= CVI_BMCR_SPEED1000;
  360. else if (CSI_ETH_SPEED_100M == priv->link_info.speed)
  361. ctl |= CVI_BMCR_SPEED100;
  362. else//CSI_ETH_SPEED_10M == priv->link_info.speed
  363. ctl |= CVI_BMCR_SPEED100;
  364. if (CSI_ETH_DUPLEX_FULL == priv->link_info.duplex)
  365. ctl |= CVI_BMCR_FULLDPLX;
  366. ret = eth_phy_write(priv, phy_addr, CVI_MII_BMCR, ctl);
  367. return ret;
  368. }
  369. int genphy_restart_aneg(eth_phy_dev_t *phy_dev)
  370. {
  371. int32_t ret;
  372. uint16_t ctl;
  373. ret = eth_phy_read(phy_dev->priv, phy_dev->phy_addr, CVI_MII_BMCR, &ctl);
  374. if (ret != 0 || ctl < 0)
  375. return ret;
  376. ctl |= (CVI_BMCR_ANENABLE | CVI_BMCR_ANRESTART);
  377. /* Don't isolate the PHY if we're negotiating */
  378. ctl &= ~(CVI_BMCR_ISOLATE);
  379. ret = eth_phy_write(phy_dev->priv, phy_dev->phy_addr, CVI_MII_BMCR, ctl);
  380. return ret;
  381. }
  382. int32_t genphy_config_aneg(eth_phy_dev_t *phy_dev)
  383. {
  384. RT_ASSERT(phy_dev->priv);
  385. eth_phy_priv_t *priv = phy_dev->priv;
  386. uint8_t phy_addr = phy_dev->phy_addr;
  387. int32_t result;
  388. uint16_t ctl;
  389. int32_t ret;
  390. if (CSI_ETH_AUTONEG_ENABLE != priv->link_info.autoneg)
  391. return genphy_setup_forced(phy_dev);
  392. result = genphy_config_advert(phy_dev);
  393. if (result < 0) /* error */
  394. return result;
  395. if (result == 0) {
  396. /* Advertisment hasn't changed, but maybe aneg was never on to
  397. * begin with? Or maybe phy was isolated? */
  398. ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &ctl);
  399. if (ret != 0 || ctl < 0)
  400. return ret;
  401. if (!(ctl & CVI_BMCR_ANENABLE) || (ctl & CVI_BMCR_ISOLATE))
  402. result = 1; /* do restart aneg */
  403. }
  404. /* Only restart aneg if we are advertising something different
  405. * than we were before. */
  406. if (result > 0)
  407. result = genphy_restart_aneg(phy_dev);
  408. return result;
  409. }
  410. int32_t genphy_config(eth_phy_dev_t *phy_dev)
  411. {
  412. RT_ASSERT(phy_dev->priv);
  413. eth_phy_priv_t *priv = phy_dev->priv;
  414. uint8_t phy_addr = phy_dev->phy_addr;
  415. int32_t ret;
  416. uint16_t val;
  417. uint32_t features;
  418. features = (CVI_SUPPORTED_TP | CVI_SUPPORTED_MII
  419. | CVI_SUPPORTED_AUI | CVI_SUPPORTED_FIBRE |
  420. CVI_SUPPORTED_BNC);
  421. /* Do we support autonegotiation? */
  422. ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &val);
  423. if (ret != 0 || val < 0)
  424. return ret;
  425. if (val & CVI_BMSR_ANEGCAPABLE)
  426. features |= CVI_SUPPORTED_Autoneg;
  427. if (val & CVI_BMSR_100FULL)
  428. features |= CVI_SUPPORTED_100baseT_Full;
  429. if (val & CVI_BMSR_100HALF)
  430. features |= CVI_SUPPORTED_100baseT_Half;
  431. if (val & CVI_BMSR_10FULL)
  432. features |= CVI_SUPPORTED_10baseT_Full;
  433. if (val & CVI_BMSR_10HALF)
  434. features |= CVI_SUPPORTED_10baseT_Half;
  435. if (val & CVI_BMSR_ESTATEN) {
  436. ret = eth_phy_read(priv, phy_addr, CVI_MII_ESTATUS, &val);
  437. if (ret != 0 || val < 0)
  438. return val;
  439. if (val & CVI_ESTATUS_1000_TFULL)
  440. features |= CVI_SUPPORTED_1000baseT_Full;
  441. if (val & CVI_ESTATUS_1000_THALF)
  442. features |= CVI_SUPPORTED_1000baseT_Half;
  443. if (val & CVI_ESTATUS_1000_XFULL)
  444. features |= CVI_SUPPORTED_1000baseX_Full;
  445. if (val & CVI_ESTATUS_1000_XHALF)
  446. features |= CVI_SUPPORTED_1000baseX_Half;
  447. }
  448. phy_dev->supported &= features;
  449. phy_dev->advertising &= features;
  450. genphy_config_aneg(phy_dev);
  451. return 0;
  452. }
  453. eth_phy_handle_t cvi_eth_phy_init(csi_eth_phy_read_t fn_read, csi_eth_phy_write_t fn_write)
  454. {
  455. eth_phy_dev_t *phy_dev;
  456. eth_phy_priv_t *priv;
  457. uint32_t phy_mask = 0xffffffff;
  458. phy_if_mode_t interface = 0;
  459. RT_ASSERT(fn_read != RT_NULL);
  460. RT_ASSERT(fn_write != RT_NULL);
  461. priv = &phy_priv_list[0];
  462. priv->phy_read = fn_read;
  463. priv->phy_write = fn_write;
  464. priv->link_info.autoneg = CSI_ETH_AUTONEG_ENABLE;
  465. phy_dev = eth_connect_phy(priv, phy_mask, interface);
  466. if (phy_dev == NULL) {
  467. rt_kprintf("No phy device found!\n");
  468. return;
  469. }
  470. rt_kprintf("connect phy id: 0x%X\n", phy_dev->phy_id);
  471. phy_dev->priv = priv;
  472. /* Reset PHY */
  473. eth_phy_reset(phy_dev);
  474. /* Config PHY */
  475. eth_phy_config(phy_dev);
  476. return phy_dev;
  477. }