drv_tsw_phy.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * Copyright (c) 2025 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-3-31 Jiading Initial version
  9. */
  10. #include "rtthread.h"
  11. #ifdef RT_USING_PHY
  12. #include <rtdevice.h>
  13. #include <rtdbg.h>
  14. #include "hpm_tsw_drv.h"
  15. #include "drv_tsw_phy.h"
  16. #include "hpm_tsw_phy.h"
  17. #include "hpm_soc.h"
  18. #include "netif/ethernetif.h"
  19. #include "board.h"
  20. typedef struct {
  21. TSW_Type *instance;
  22. uint8_t port;
  23. } tsw_phy_instance_t;
  24. typedef struct
  25. {
  26. char *mdio_name;
  27. tsw_phy_instance_t *phy_ins;
  28. struct eth_device *eth_dev;
  29. phy_device_t *phy_dev;
  30. struct rt_mdio_bus *mdio_bus;
  31. } tsw_phy_handle_t;
  32. typedef struct
  33. {
  34. uint8_t phy_handle_cnt;
  35. tsw_phy_handle_t **phy_handle;
  36. } tsw_phy_monitor_handle_t;
  37. extern struct eth_device eth0_dev;
  38. static phy_device_t phy0_dev;
  39. static struct rt_mdio_bus_ops mdio0_bus_ops;
  40. static struct rt_mdio_bus mdio0_bus = {.ops = &mdio0_bus_ops};
  41. static tsw_phy_instance_t instance = {.instance = BOARD_TSW,
  42. .port = BOARD_TSW_PORT
  43. };
  44. static tsw_phy_handle_t tsw_phy_handle = {
  45. .phy_ins = &instance,
  46. .eth_dev = &eth0_dev,
  47. .phy_dev = &phy0_dev,
  48. .mdio_name = "MDIO0",
  49. .mdio_bus = &mdio0_bus,
  50. };
  51. static tsw_phy_handle_t *s_gphys[] = {
  52. &tsw_phy_handle
  53. };
  54. tsw_phy_monitor_handle_t phy_monitor_handle = {
  55. .phy_handle_cnt = ARRAY_SIZE(s_gphys),
  56. .phy_handle = s_gphys
  57. };
  58. static struct rt_phy_ops phy_ops;
  59. static rt_phy_status phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz)
  60. {
  61. tsw_phy_instance_t *phy_ins = (tsw_phy_instance_t *)object;
  62. if (phy_ins->instance == HPM_TSW) {
  63. rtl8211_config_t phy_config;
  64. /* Set MDC clock frequency */
  65. tsw_ep_set_mdio_config(phy_ins->instance, phy_ins->port, src_clock_hz / (2 * PHY_MDIO_CLK_FREQ) - 1);
  66. /* PHY Reset */
  67. rtl8211_reset(phy_ins->instance, phy_ins->port);
  68. rtl8211_basic_mode_default_config(phy_ins->instance, &phy_config);
  69. if (rtl8211_basic_mode_init(phy_ins->instance, phy_ins->port, &phy_config) == true) {
  70. return PHY_STATUS_OK;
  71. } else {
  72. return PHY_STATUS_FAIL;
  73. }
  74. }
  75. return -RT_EINVAL;
  76. }
  77. static rt_size_t phy_read(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
  78. {
  79. hpm_stat_t stat;
  80. tsw_phy_instance_t *phy_ins = ((struct rt_mdio_bus *)bus)->hw_obj;
  81. stat = tsw_ep_mdio_read(phy_ins->instance, phy_ins->port, addr, reg, (uint16_t *)data);
  82. if (stat == status_success) {
  83. return size;
  84. } else {
  85. return 0;
  86. }
  87. }
  88. static rt_size_t phy_write(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
  89. {
  90. hpm_stat_t stat;
  91. tsw_phy_instance_t *phy_ins = ((struct rt_mdio_bus *)bus)->hw_obj;
  92. stat = tsw_ep_mdio_write(phy_ins->instance, phy_ins->port, addr, reg, *(uint16_t *)data);
  93. if (stat == status_success) {
  94. return size;
  95. } else {
  96. return 0;
  97. }
  98. }
  99. static rt_phy_status phy_get_link_status(rt_phy_t *phy, rt_bool_t *status)
  100. {
  101. tsw_phy_instance_t *phy_ins = phy->bus->hw_obj;
  102. tsw_phy_status_t phy_status;
  103. if (phy_ins->instance == HPM_TSW) {
  104. #if defined(__USE_RTL8211) && __USE_RTL8211
  105. rtl8211_get_phy_status(phy_ins->instance, phy_ins->port, &phy_status);
  106. #endif
  107. }
  108. *status = phy_status.tsw_phy_link;
  109. return PHY_STATUS_OK;
  110. }
  111. static rt_phy_status phy_get_link_speed_duplex(rt_phy_t *phy, rt_uint32_t *speed, rt_uint32_t *duplex)
  112. {
  113. tsw_phy_instance_t *phy_ins = phy->bus->hw_obj;
  114. tsw_phy_status_t phy_status;
  115. if (phy_ins->instance == HPM_TSW) {
  116. #if defined(__USE_RTL8211) && __USE_RTL8211
  117. rtl8211_get_phy_status(phy_ins->instance, phy_ins->port, &phy_status);
  118. #endif
  119. }
  120. *speed = phy_status.tsw_phy_speed;
  121. *duplex = phy_status.tsw_phy_duplex;
  122. return PHY_STATUS_OK;
  123. }
  124. static void phy_poll_status(void *parameter)
  125. {
  126. int ret;
  127. phy_info_t phy_info;
  128. rt_bool_t status;
  129. rt_device_t dev;
  130. rt_phy_msg_t msg;
  131. rt_uint32_t speed, duplex;
  132. phy_device_t *phy_dev;
  133. struct eth_device* eth_dev;
  134. char const *ps[] = {"10Mbps", "100Mbps", "1000Mbps"};
  135. tsw_port_speed_t port_speed[] = {tsw_port_speed_10mbps, tsw_port_speed_100mbps, tsw_port_speed_1000mbps};
  136. tsw_phy_monitor_handle_t *phy_monitor_handle = (tsw_phy_monitor_handle_t *)parameter;
  137. for (uint32_t i = 0; i < phy_monitor_handle->phy_handle_cnt; i++) {
  138. eth_dev = phy_monitor_handle->phy_handle[i]->eth_dev;
  139. phy_dev = phy_monitor_handle->phy_handle[i]->phy_dev;
  140. phy_dev->phy.ops->get_link_status(&phy_dev->phy, &status);
  141. if (status) {
  142. phy_dev->phy.ops->get_link_speed_duplex(&phy_dev->phy, &phy_info.phy_speed, &phy_info.phy_duplex);
  143. ret = memcmp(&phy_dev->phy_info, &phy_info, sizeof(phy_info_t));
  144. if (ret != 0) {
  145. memcpy(&phy_dev->phy_info, &phy_info, sizeof(phy_info_t));
  146. }
  147. }
  148. if (phy_dev->phy_link != status) {
  149. phy_dev->phy_link = status ? PHY_LINK_UP : PHY_LINK_DOWN;
  150. eth_device_linkchange(eth_dev, status);
  151. LOG_I("PHY Status: %s", status ? "Link up" : "Link down\n");
  152. if (status == PHY_LINK_UP) {
  153. LOG_I("PHY Speed: %s", ps[phy_dev->phy_info.phy_speed]);
  154. LOG_I("PHY Duplex: %s\n", phy_dev->phy_info.phy_duplex & PHY_FULL_DUPLEX ? "full duplex" : "half duplex");
  155. tsw_set_port_speed(phy_monitor_handle->phy_handle[i]->phy_ins->instance, phy_monitor_handle->phy_handle[i]->phy_ins->port, port_speed[phy_dev->phy_info.phy_speed]);
  156. if (!(phy_dev->phy_info.phy_duplex & PHY_FULL_DUPLEX)) {
  157. LOG_E("Error: PHY is in half duplex now, but TSW MAC supports only full duplex mode!\n");
  158. return;
  159. }
  160. }
  161. }
  162. }
  163. }
  164. static void phy_detection(void *parameter)
  165. {
  166. phy_device_t *phy_dev = (phy_device_t *)parameter;
  167. if (phy_dev->phy.ops->init(phy_dev->phy.bus->hw_obj, 0, PHY_MDIO_CSR_CLK_FREQ) != PHY_STATUS_OK) {
  168. LOG_E("No any PHY device is detected! Please check your hardware!\n");
  169. }
  170. return;
  171. }
  172. static void phy_monitor_thread_entry(void *args)
  173. {
  174. rt_timer_t phy_status_timer;
  175. tsw_phy_monitor_handle_t *phy_monitor_handle = (tsw_phy_monitor_handle_t *)args;
  176. for (uint32_t i = 0; i < phy_monitor_handle->phy_handle_cnt; i++) {
  177. LOG_D("Detect a PHY%d\n", i);
  178. phy_detection(phy_monitor_handle->phy_handle[i]->phy_dev);
  179. }
  180. phy_status_timer = rt_timer_create("PHY_Monitor", phy_poll_status, phy_monitor_handle, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
  181. if (!phy_status_timer || rt_timer_start(phy_status_timer) != RT_EOK) {
  182. LOG_E("Failed to start link change detection timer\n");
  183. }
  184. }
  185. int phy_device_register(void)
  186. {
  187. rt_err_t err = -RT_ERROR;
  188. rt_thread_t thread_phy_monitor;
  189. /* Set ops for PHY */
  190. phy_ops.init = phy_init;
  191. phy_ops.get_link_status = phy_get_link_status;
  192. phy_ops.get_link_speed_duplex = phy_get_link_speed_duplex;
  193. for (uint32_t i = 0; i < ARRAY_SIZE(s_gphys); i++) {
  194. /* Set PHY address */
  195. s_gphys[i]->phy_dev->phy.addr = 0xffff;
  196. /* Set MIDO bus */
  197. s_gphys[i]->mdio_bus->hw_obj = s_gphys[i]->phy_ins;
  198. s_gphys[i]->mdio_bus->name = s_gphys[i]->mdio_name;
  199. s_gphys[i]->mdio_bus->ops->read = phy_read;
  200. s_gphys[i]->mdio_bus->ops->write = phy_write;
  201. s_gphys[i]->phy_dev->phy.bus = s_gphys[i]->mdio_bus;
  202. s_gphys[i]->phy_dev->phy.ops = &phy_ops;
  203. rt_hw_phy_register(&s_gphys[i]->phy_dev->phy, NULL);
  204. }
  205. /* Start PHY monitor */
  206. thread_phy_monitor = rt_thread_create("PHY Monitor", phy_monitor_thread_entry, &phy_monitor_handle, 4096, RT_THREAD_PRIORITY_MAX - 2, 2);
  207. if (thread_phy_monitor != RT_NULL) {
  208. rt_thread_startup(thread_phy_monitor);
  209. } else {
  210. err = -RT_ERROR;
  211. }
  212. return err;
  213. }
  214. INIT_PREV_EXPORT(phy_device_register);
  215. #endif /* RT_USING_PHY */