cvi_eth_phy.c 15 KB

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