fgmac_phy.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * Copyright : (C) 2022 Phytium Information Technology, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is OPEN SOURCE software: you can redistribute it and/or modify it
  6. * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
  7. * either version 1.0 of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  10. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the Phytium Public License for more details.
  12. *
  13. *
  14. * FilePath: fgmac_phy.c
  15. * Date: 2022-04-06 14:46:52
  16. * LastEditTime: 2022-04-06 14:46:53
  17. * Description:  This file is for
  18. *
  19. * Modify History:
  20. * Ver   Who        Date         Changes
  21. * ----- ------     --------    --------------------------------------
  22. */
  23. /***************************** Include Files *********************************/
  24. #include "fassert.h"
  25. #include "fio.h"
  26. #include "ferror_code.h"
  27. #include "ftypes.h"
  28. #include "fdebug.h"
  29. #include "fparameters.h"
  30. #include "fgmac_hw.h"
  31. #include "fgmac_phy.h"
  32. #include "fgmac.h"
  33. #ifdef CONFIG_FGMAC_PHY_AR803X
  34. #include "fgmac_ar803x.h"
  35. #endif
  36. #include "fsleep.h"
  37. /************************** Constant Definitions *****************************/
  38. /**************************** Type Definitions *******************************/
  39. /***************** Macros (Inline Functions) Definitions *********************/
  40. #define FGMAC_DEBUG_TAG "FGMAC-PHY"
  41. #define FGMAC_ERROR(format, ...) FT_DEBUG_PRINT_E(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
  42. #define FGMAC_WARN(format, ...) FT_DEBUG_PRINT_W(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
  43. #define FGMAC_INFO(format, ...) FT_DEBUG_PRINT_I(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
  44. #define FGMAC_DEBUG(format, ...) FT_DEBUG_PRINT_D(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
  45. /************************** Function Prototypes ******************************/
  46. /************************** Variable Definitions *****************************/
  47. /*****************************************************************************/
  48. /* 此文件主要为了完成用户对外接口,用户可以使用这些接口直接开始工作 */
  49. /* - 包括用户API的定义和实现
  50. - 同时包含必要的OPTION方法,方便用户进行配置
  51. - 如果驱动可以直接进行I/O操作,在此源文件下可以将API 进行实现 */
  52. /* - 包括用户API的定义和实现
  53. - 同时包含必要的OPTION方法,方便用户进行配置
  54. - 如果驱动可以直接进行I/O操作,在此源文件下可以将API 进行实现 */
  55. /**
  56. * @name: FGmacWaitPhyAutoNegotiationEnd
  57. * @msg: wait fgmac phy auto negotiation complete
  58. * @param {FGmac} *instance_p, instance of FGmac controller
  59. * @param {u32} phy_address, phy address connect to fgmac
  60. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  61. */
  62. static FError FGmacWaitPhyAutoNegotiationEnd(FGmac *instance_p, u32 phy_address)
  63. {
  64. u16 reg_val;
  65. FError ret = FGMAC_SUCCESS;
  66. int timeout = FGMAC_RETRY_TIMES;
  67. do
  68. {
  69. reg_val = 0;
  70. ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_STATUS_REG, &reg_val);
  71. if (FGMAC_SUCCESS != ret)
  72. break;
  73. fsleep_millisec(20);
  74. }
  75. while ((FGMAC_PHY_MII_SR_AUTO_NEGOT_COMPLETE != (FGMAC_PHY_MII_SR_AUTO_NEGOT_COMPLETE & reg_val)) &&
  76. (0 < --timeout));
  77. if (FGMAC_SUCCESS != ret)
  78. return ret;
  79. if (0 >= timeout)
  80. {
  81. FGMAC_ERROR("auto negotiation timeout, reg_val: %#x", reg_val);
  82. ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, &reg_val);
  83. FGMAC_ERROR("auto negotiation timeout, FGMAC_PHY_MII_CTRL_REG reg_val: %#x", reg_val);
  84. ret = FGMAC_ERR_TIMEOUT;
  85. }
  86. return ret;
  87. }
  88. /**
  89. * @name: FGmacPhyAutoNegotiation
  90. * @msg: fgmac phy auto negotiation configuration
  91. * @param {FGmac} *instance_p, instance of FGmac controller
  92. * @param {u32} phy_address, phy address connect to fgmac
  93. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  94. */
  95. static FError FGmacPhyAutoNegotiation(FGmac *instance_p, u32 phy_address)
  96. {
  97. FASSERT(instance_p);
  98. u16 reg_val;
  99. FError ret = FGMAC_SUCCESS;
  100. int timeout = FGMAC_RETRY_TIMES;
  101. /* check link state */
  102. do
  103. {
  104. reg_val = 0;
  105. ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_STATUS_REG, &reg_val);
  106. if (FGMAC_SUCCESS != ret)
  107. break;
  108. fsleep_millisec(20);
  109. }
  110. while (!(reg_val & FGMAC_PHY_MII_SR_LSTATUS) && (0 <= --timeout));
  111. if (0 >= timeout)
  112. {
  113. FGMAC_ERROR("timeout when wait phy auto negotiation ");
  114. return FGMAC_ERR_TIMEOUT;
  115. }
  116. if (FGMAC_SUCCESS != ret)
  117. return ret;
  118. ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, &reg_val);
  119. if (FGMAC_SUCCESS != ret)
  120. {
  121. FGMAC_ERROR("auto negotiation failed");
  122. return ret;
  123. }
  124. reg_val |= FGMAC_PHY_MII_CR_AUTO_NEGOT;
  125. ret = FGmacWritePhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, reg_val);
  126. if (FGMAC_SUCCESS != ret)
  127. {
  128. FGMAC_ERROR("auto negotiation failed");
  129. return ret;
  130. }
  131. ret = FGmacWaitPhyAutoNegotiationEnd(instance_p, phy_address);
  132. if (FGMAC_SUCCESS != ret)
  133. return ret;
  134. return ret;
  135. }
  136. /**
  137. * @name: FGmacPhyNoneNegotiation
  138. * @msg: fgmac phy not negotiation configuration
  139. * @param {FGmac} *instance_p, instance of FGmac controller
  140. * @param {u32} phy_address, phy address connect to fgmac
  141. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  142. */
  143. static FError FGmacPhyNoneNegotiation(FGmac *instance_p, u32 phy_address)
  144. {
  145. FASSERT(instance_p);
  146. u16 control_reg = 0;
  147. FError ret = FGMAC_SUCCESS;
  148. /* read phy control register */
  149. ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, &control_reg);
  150. if (FGMAC_SUCCESS != ret)
  151. return ret;
  152. /* 设置半双工模式 */
  153. if (FGMAC_PHY_MODE_FULLDUPLEX == instance_p->config.duplex_mode)
  154. control_reg |= FGMAC_PHY_MII_CR_DUPLEX_MODE;
  155. else
  156. control_reg &= ~(FGMAC_PHY_MII_CR_DUPLEX_MODE);
  157. /* 设置速度bit6|bit13, 10b-1000M, 01b-100M, 00b-10M */
  158. switch (instance_p->config.speed)
  159. {
  160. case FGMAC_PHY_SPEED_1000:
  161. control_reg |= FGMAC_PHY_MII_CR_SPEED_SEL_MSB;
  162. control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_LSB);
  163. break;
  164. case FGMAC_PHY_SPEED_100:
  165. control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_MSB);
  166. control_reg |= FGMAC_PHY_MII_CR_SPEED_SEL_LSB;
  167. break;
  168. case FGMAC_PHY_SPEED_10:
  169. control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_MSB);
  170. control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_LSB);
  171. break;
  172. default:
  173. FASSERT(0);
  174. break;
  175. }
  176. /* disable auto-negotiation */
  177. control_reg &= ~(FGMAC_PHY_MII_CR_AUTO_NEGOT);
  178. control_reg &= ~(FGMAC_PHY_MII_CR_RESTART_AUTO_NEGO);
  179. /* write phy control register */
  180. ret = FGmacWritePhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, control_reg);
  181. if (FGMAC_SUCCESS != ret)
  182. {
  183. FGMAC_ERROR("disable auto-negotiation failed");
  184. return ret;
  185. }
  186. return ret;
  187. }
  188. /**
  189. * @name: FGmacWritePhyReg
  190. * @msg: write phy register value
  191. * @param {FGmac} *instance_p, instance of FGmac controller
  192. * @param {u32} phy_address, phy address connect to fgmac
  193. * @param {u16} phy_reg, phy register offset to write
  194. * @param {u16} phy_reg_val, value write to phy register
  195. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  196. */
  197. FError FGmacWritePhyReg(FGmac *instance_p, u32 phy_address, u16 phy_reg, u16 phy_reg_val)
  198. {
  199. FASSERT(instance_p);
  200. u32 cmd_reg_val;
  201. uintptr base_addr = instance_p->config.base_addr;
  202. FError ret = FGMAC_SUCCESS;
  203. cmd_reg_val = FGMAC_MII_ADDR_CR(instance_p->config.mdc_clk_hz);
  204. cmd_reg_val |= FGMAC_MII_ADDR_PA(phy_address);
  205. cmd_reg_val |= FGMAC_MII_ADDR_GR(phy_reg);
  206. cmd_reg_val |= FGMAC_MII_ADDR_GW;
  207. cmd_reg_val |= FGMAC_MII_ADDR_GB;
  208. FGMAC_WRITE_REG32(base_addr, FGMAC_GMII_DATA_OFFSET, phy_reg_val);
  209. FGMAC_WRITE_REG32(base_addr, FGMAC_GMII_ADDR_OFFSET, cmd_reg_val);
  210. ret = FGmacPhyWaitBusBusy(base_addr, FGMAC_RETRY_TIMES);
  211. return ret;
  212. }
  213. /**
  214. * @name: FGmacReadPhyReg
  215. * @msg: read phy register value
  216. * @param {FGmac} *instance_p, instance of FGmac controller
  217. * @param {u32} phy_address, phy address connect to fgmac
  218. * @param {u16} phy_reg, phy register offset to read
  219. * @param {u16} *phy_reg_val_p, phy register value pointer
  220. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  221. */
  222. FError FGmacReadPhyReg(FGmac *instance_p, u32 phy_address, u16 phy_reg, u16 *phy_reg_val_p)
  223. {
  224. FASSERT(instance_p && phy_reg_val_p);
  225. u32 cmd_reg_val;
  226. uintptr base_addr = instance_p->config.base_addr;
  227. FError ret = FGMAC_SUCCESS;
  228. cmd_reg_val = FGMAC_MII_ADDR_CR(instance_p->config.mdc_clk_hz);
  229. cmd_reg_val |= FGMAC_MII_ADDR_PA(phy_address);
  230. cmd_reg_val |= FGMAC_MII_ADDR_GR(phy_reg);
  231. cmd_reg_val &= ~FGMAC_MII_ADDR_GW;
  232. cmd_reg_val |= FGMAC_MII_ADDR_GB;
  233. ret = FGmacPhyWaitBusBusy(base_addr, FGMAC_RETRY_TIMES);
  234. if (FGMAC_SUCCESS != ret)
  235. return ret;
  236. FGMAC_WRITE_REG32(base_addr, FGMAC_GMII_ADDR_OFFSET, cmd_reg_val);
  237. ret = FGmacPhyWaitBusBusy(base_addr, FGMAC_RETRY_TIMES);
  238. if (FGMAC_SUCCESS != ret)
  239. return ret;
  240. *phy_reg_val_p = FGMAC_MII_DATA_GD_MASK & FGMAC_READ_REG32(base_addr, FGMAC_GMII_DATA_OFFSET);
  241. return ret;
  242. }
  243. /**
  244. * @name: FGmacPhyDetect
  245. * @msg: detect fgmac phy, and get phy addr
  246. * @param {FGmac} *instance_p, instance of FGmac controller
  247. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  248. */
  249. FError FGmacPhyDetect(FGmac *instance_p)
  250. {
  251. u32 phy_addr = 0;
  252. u16 phy_reg = 0, phy_id1_reg, phy_id2_reg;
  253. FError ret = FGMAC_SUCCESS;
  254. u32 invalid_count = 0;
  255. for (phy_addr = 0; phy_addr < FGMAC_PHY_MAX_NUM; phy_addr++)
  256. {
  257. ret = FGmacReadPhyReg(instance_p, phy_addr, FGMAC_PHY_MII_STATUS_REG, &phy_reg);
  258. if (ret != FGMAC_SUCCESS)
  259. {
  260. FGMAC_ERROR("%s, PHY operation is busy", __func__);
  261. return ret;
  262. }
  263. if (phy_reg != 0xffff)
  264. {
  265. ret = FGmacReadPhyReg(instance_p, phy_addr, FGMAC_PHY_MII_PHYSID1_REG, &phy_id1_reg);
  266. ret |= FGmacReadPhyReg(instance_p, phy_addr, FGMAC_PHY_MII_PHYSID2_REG, &phy_id2_reg);
  267. if ((ret == FGMAC_SUCCESS) && (phy_id1_reg != 0xffff) && (phy_id2_reg != 0xffff))
  268. {
  269. /* assign the max valid phy address to instance_p->phy_addr */
  270. instance_p->phy_addr = phy_addr;
  271. instance_p->phy_valid_mask |= (1 << phy_addr);
  272. instance_p->phy_id1 = phy_id1_reg;
  273. FGMAC_INFO("phy_addr: [%d], phy_valid_mask: 0x%x, phy id: [0x%08x][0x%08x], phy_reg:0x%x",
  274. phy_addr, instance_p->phy_valid_mask, phy_id1_reg, phy_id2_reg, phy_reg);
  275. return ret;
  276. }
  277. }
  278. else
  279. {
  280. invalid_count++;
  281. }
  282. }
  283. if (invalid_count == FGMAC_PHY_MAX_NUM)
  284. {
  285. FGMAC_ERROR("phy detect failed, phy address is not found!");
  286. return FGMAC_ERR_PHY_IS_NOT_FOUND;
  287. }
  288. return FGMAC_SUCCESS;
  289. }
  290. /**
  291. * @name: FGmacPhyReset
  292. * @msg: detect fgmac phy, and get phy addr
  293. * @param {FGmac} *instance_p, instance of FGmac controller
  294. * @param {u32} phy_address, phy address connect to fgmac
  295. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  296. */
  297. FError FGmacPhyReset(FGmac *instance_p, u32 phy_address)
  298. {
  299. FError ret = FGMAC_ERR_PHY_NOT_SUPPORT;
  300. uintptr base_addr = instance_p->config.base_addr;
  301. ret = FGmacWritePhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, FGMAC_PHY_MII_CR_RESET);
  302. if (FGMAC_SUCCESS != ret)
  303. {
  304. FGMAC_ERROR("reset phy failed");
  305. return ret;
  306. }
  307. return FGMAC_SUCCESS;
  308. }
  309. /**
  310. * @name: FGmacGetPhySpecialStatus
  311. * @msg: read phy special status register to get speed and duplex mode
  312. * @param {FGmac} *instance_p, instance of FGmac controller
  313. * @param {u32} phy_address, phy address connect to fgmac
  314. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  315. */
  316. static FError FGmacGetPhySpecialStatus(FGmac *instance_p, u32 phy_address)
  317. {
  318. u16 phy_special_status = 0;
  319. u32 ret = FGMAC_SUCCESS;
  320. ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_PHY_SPECIAL_REG, &phy_special_status);
  321. if (FGMAC_SUCCESS != ret)
  322. {
  323. return ret;
  324. }
  325. switch (phy_special_status & FGMAC_PHY_SPECIFIC_STATUS_SPEED_MASK)
  326. {
  327. case FGMAC_PHY_SPECIFIC_STATUS_SPEED_1000M:
  328. instance_p->config.speed = FGMAC_PHY_SPEED_1000;
  329. break;
  330. case FGMAC_PHY_SPECIFIC_STATUS_SPEED_100M:
  331. instance_p->config.speed = FGMAC_PHY_SPEED_100;
  332. break;
  333. case FGMAC_PHY_SPECIFIC_STATUS_SPEED_10M:
  334. instance_p->config.speed = FGMAC_PHY_SPEED_10;
  335. break;
  336. default:
  337. break;
  338. }
  339. if (phy_special_status & FGMAC_PHY_SPECIFIC_STATUS_DUPLEX_MASK)
  340. instance_p->config.duplex_mode = FGMAC_PHY_MODE_FULLDUPLEX;
  341. else
  342. instance_p->config.duplex_mode = FGMAC_PHY_MODE_HALFDUPLEX;
  343. return ret;
  344. }
  345. /**
  346. * @name: FGmacPhyCfgInitialize
  347. * @msg: fgmac phy configuration
  348. * @param {FGmac} *instance_p, instance of FGmac controller
  349. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  350. */
  351. FError FGmacPhyCfgInitialize(FGmac *instance_p)
  352. {
  353. FASSERT(instance_p);
  354. uintptr base_addr = instance_p->config.base_addr;
  355. FError ret = FGMAC_SUCCESS;
  356. u32 phy_addr;
  357. /* detect phy address, and assigned the minimum valid address to phy_addr */
  358. ret = FGmacPhyDetect(instance_p);
  359. if (FGMAC_SUCCESS != ret)
  360. {
  361. FGMAC_ERROR("phy detect failed!");
  362. return ret;
  363. }
  364. for (phy_addr = 0; phy_addr <= instance_p->phy_addr; phy_addr++)
  365. {
  366. /* 计算出当前位置 */
  367. if (instance_p->phy_valid_mask & (1 << phy_addr))
  368. {
  369. /* set phy power down and set phy Normal operation */
  370. FGmacPhyReset(instance_p, phy_addr);
  371. /* auto negotiation */
  372. if (instance_p->config.en_auto_negtiation)
  373. {
  374. ret = FGmacPhyAutoNegotiation(instance_p, phy_addr);
  375. if (FGMAC_SUCCESS != ret)
  376. {
  377. FGMAC_ERROR("auto negotiation phy failed");
  378. return ret;
  379. }
  380. }
  381. else
  382. {
  383. /* if gmac is disable auto negotiation, we need set speed */
  384. ret = FGmacPhyNoneNegotiation(instance_p, phy_addr);
  385. if (FGMAC_SUCCESS != ret)
  386. {
  387. FGMAC_ERROR("negotiation phy failed");
  388. return ret;
  389. }
  390. }
  391. /* read phy special status register to get speed and duplex mode */
  392. ret = FGmacGetPhySpecialStatus(instance_p, phy_addr);
  393. if (FGMAC_SUCCESS != ret)
  394. {
  395. FGMAC_ERROR("get phy special status failed");
  396. return ret;
  397. }
  398. FGMAC_DEBUG("instance_p->config.speed: %d", instance_p->config.speed);
  399. FGMAC_DEBUG("instance_p->config.duplex_mode: 0x%x", instance_p->config.duplex_mode);
  400. /* update mac controller speed setting */
  401. FGmacControllerSpeedConfig(instance_p, instance_p->config.speed);
  402. /* update mac controller duplex mode setting */
  403. FGmacControllerDuplexConfig(instance_p, instance_p->config.duplex_mode);
  404. }
  405. }
  406. return ret;
  407. }
  408. FError FGmacPhyCfgDeInitialize(FGmac *instance_p)
  409. {
  410. FASSERT(instance_p);
  411. uintptr base_addr = instance_p->config.base_addr;
  412. FError ret = FGMAC_SUCCESS;
  413. u32 phy_addr;
  414. for (phy_addr = 0; phy_addr <= instance_p->phy_addr; phy_addr++)
  415. {
  416. /* 计算出当前位置 */
  417. if (instance_p->phy_valid_mask & (1 << phy_addr))
  418. {
  419. /* set phy power down and set phy Normal operation */
  420. FGmacPhyReset(instance_p, phy_addr);
  421. }
  422. }
  423. return ret;
  424. }
  425. /**
  426. * @name: FGmacPhyAwaken
  427. * @msg: fgmac phy awaken
  428. * @param {FGmac} *instance_p, instance of FGmac controller
  429. * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
  430. */
  431. FError FGmacPhyAwaken(FGmac *instance_p)
  432. {
  433. FError ret = FGMAC_SUCCESS;
  434. #ifdef CONFIG_FGMAC_PHY_AR803X
  435. ret = FGmacPhyDetect(instance_p);
  436. if (FGMAC_SUCCESS != ret)
  437. {
  438. FGMAC_ERROR("phy detect failed!");
  439. return ret;
  440. }
  441. u16 phy_id1;
  442. phy_id1 = instance_p->phy_id1;
  443. if (phy_id1 == FGMAC_AR803X_PHY_ID1)
  444. {
  445. ret = FGmacAr803xDisableHibernate(instance_p);
  446. }
  447. #endif
  448. return ret;
  449. }