1 /*
2  * Copyright (c) 2023-2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Change Logs:
7  * Date         Author      Notes
8  * 2023-12-20   Jiading     Optimization for all-in-one version
9  * 2024-04-17   Jiading     Support multiple PHYs
10  */
11 
12 #include "rtthread.h"
13 
14 #ifdef RT_USING_PHY
15 #include <rtdevice.h>
16 #include <rtdbg.h>
17 #include "hpm_enet_drv.h"
18 #include "drv_enet_phy.h"
19 #include "hpm_enet_phy.h"
20 #include "hpm_soc.h"
21 #include "netif/ethernetif.h"
22 #include "board.h"
23 
24 typedef struct
25 {
26     char *mdio_name;
27     ENET_Type *instance;
28     struct eth_device *eth_dev;
29     phy_device_t *phy_dev;
30     struct rt_mdio_bus *mdio_bus;
31 } eth_phy_handle_t;
32 
33 typedef struct
34 {
35     uint8_t phy_handle_cnt;
36     eth_phy_handle_t **phy_handle;
37 } eth_phy_monitor_handle_t;
38 
39 #ifdef BSP_USING_ETH0
40 extern struct eth_device eth0_dev;
41 static struct rt_mdio_bus_ops mdio0_bus_ops;
42 static struct rt_mdio_bus mdio0_bus = {.ops = &mdio0_bus_ops};
43 static phy_device_t phy0_dev;
44 
45 static eth_phy_handle_t eth0_phy_handle =
46 {
47     .instance  = HPM_ENET0,
48     .eth_dev   = &eth0_dev,
49     .phy_dev   = &phy0_dev,
50     .mdio_name = "MDIO0",
51     .mdio_bus  = &mdio0_bus,
52 };
53 #endif
54 
55 #ifdef BSP_USING_ETH1
56 extern struct eth_device eth1_dev;
57 static struct rt_mdio_bus_ops mdio1_bus_ops;
58 static struct rt_mdio_bus mdio1_bus = {.ops = &mdio1_bus_ops};
59 static phy_device_t phy1_dev;
60 
61 static eth_phy_handle_t eth1_phy_handle =
62 {
63     .instance     = HPM_ENET1,
64     .eth_dev      = &eth1_dev,
65     .phy_dev      = &phy1_dev,
66     .mdio_name    = "MDIO1",
67     .mdio_bus     = &mdio1_bus,
68 };
69 #endif
70 
71 static eth_phy_handle_t *s_gphys[] =
72 {
73 #ifdef BSP_USING_ETH0
74 &eth0_phy_handle,
75 #endif
76 
77 #ifdef BSP_USING_ETH1
78 &eth1_phy_handle
79 #endif
80 };
81 
82 eth_phy_monitor_handle_t phy_monitor_handle =
83 {
84     .phy_handle_cnt = ARRAY_SIZE(s_gphys),
85     .phy_handle     = s_gphys
86 };
87 
88 static struct rt_phy_ops phy_ops;
89 
phy_init(void * object,rt_uint32_t phy_addr,rt_uint32_t src_clock_hz)90 static rt_phy_status phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz)
91 {
92 #if defined(BSP_USING_ETH0) && defined(BSP_USING_ENET_PHY_DP83867)
93     if ((ENET_Type *)object == HPM_ENET0)
94     {
95        dp83867_config_t phy_config;
96 
97        dp83867_reset((ENET_Type *)object);
98        #if defined(__DISABLE_AUTO_NEGO) && __DISABLE_AUTO_NEGO
99        dp83867_set_mdi_crossover_mode((ENET_Type *)object, enet_phy_mdi_crossover_manual_mdix);
100        #endif
101        dp83867_basic_mode_default_config((ENET_Type *)object, &phy_config);
102        if (dp83867_basic_mode_init((ENET_Type *)object, &phy_config) == true) {
103            return PHY_STATUS_OK;
104        } else {
105         return PHY_STATUS_FAIL;
106        }
107     }
108 #endif
109 
110 
111 #if defined(BSP_USING_ETH0) && defined(BSP_USING_ENET_PHY_RTL8211)
112     if ((ENET_Type *)object == HPM_ENET0)
113     {
114         rtl8211_config_t phy_config;
115 
116         rtl8211_reset((ENET_Type *)object);
117         rtl8211_basic_mode_default_config((ENET_Type *)object, &phy_config);
118         if (rtl8211_basic_mode_init((ENET_Type *)object, &phy_config) == true) {
119             return PHY_STATUS_OK;
120         } else {
121             return PHY_STATUS_FAIL;
122         }
123     }
124 #endif
125 
126 #if defined(BSP_USING_ETH0) && defined(BSP_USING_ENET_PHY_RTL8201) && !defined(BSP_USING_ETH1)
127     if ((ENET_Type *)object == HPM_ENET0)
128     {
129         rtl8201_config_t phy_config;
130 
131         rtl8201_reset((ENET_Type *)object);
132         rtl8201_basic_mode_default_config((ENET_Type *)object, &phy_config);
133         if (rtl8201_basic_mode_init((ENET_Type *)object, &phy_config) == true) {
134             return PHY_STATUS_OK;
135         } else {
136             return PHY_STATUS_FAIL;
137         }
138     }
139 #endif
140 
141 #if defined(BSP_USING_ETH1) && defined(BSP_USING_ENET_PHY_DP83848)
142     if ((ENET_Type *)object == HPM_ENET1)
143     {
144         dp83848_config_t phy_config;
145 
146         dp83848_reset((ENET_Type *)object);
147         dp83848_basic_mode_default_config((ENET_Type *)object, &phy_config);
148         if (dp83848_basic_mode_init((ENET_Type *)object, &phy_config) == true) {
149             return PHY_STATUS_OK;
150         } else {
151             return PHY_STATUS_FAIL;
152         }
153     }
154 #endif
155 
156 #if defined(BSP_USING_ETH1) && defined(BSP_USING_ENET_PHY_RTL8201)
157     if ((ENET_Type *)object == HPM_ENET1)
158     {
159         rtl8201_config_t phy_config;
160 
161         rtl8201_reset((ENET_Type *)object);
162         rtl8201_basic_mode_default_config((ENET_Type *)object, &phy_config);
163         if (rtl8201_basic_mode_init((ENET_Type *)object, &phy_config) == true) {
164             return PHY_STATUS_OK;
165         } else {
166             return PHY_STATUS_FAIL;
167         }
168     }
169 #endif
170 
171 #if defined(BSP_USING_ETH1) && defined(BSP_USING_ENET_PHY_LAN8720)
172     if ((ENET_Type *)object == HPM_ENET1)
173     {
174         lan8720_config_t phy_config;
175 
176         lan8720_reset((ENET_Type *)object);
177         lan8720_basic_mode_default_config((ENET_Type *)object, &phy_config);
178         if (lan8720_basic_mode_init((ENET_Type *)object, &phy_config) == true) {
179             return PHY_STATUS_OK;
180         } else {
181             return PHY_STATUS_FAIL;
182         }
183     }
184 #endif
185 }
186 
phy_read(void * bus,rt_uint32_t addr,rt_uint32_t reg,void * data,rt_uint32_t size)187 static rt_size_t phy_read(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
188 {
189     *(uint16_t *)data = enet_read_phy(((struct rt_mdio_bus *)bus)->hw_obj, addr, reg);
190 
191     return size;
192 }
193 
phy_write(void * bus,rt_uint32_t addr,rt_uint32_t reg,void * data,rt_uint32_t size)194 static rt_size_t phy_write(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
195 {
196     enet_write_phy(((struct rt_mdio_bus *)bus)->hw_obj, addr, reg,  *(uint16_t *)data);
197 
198     return size;
199 }
200 
phy_get_link_status(rt_phy_t * phy,rt_bool_t * status)201 static rt_phy_status phy_get_link_status(rt_phy_t *phy, rt_bool_t *status)
202 {
203     enet_phy_status_t phy_status;
204 
205     if (phy->bus->hw_obj == HPM_ENET0)
206     {
207         #if defined(__USE_DP83867) && __USE_DP83867
208         dp83867_get_phy_status(phy->bus->hw_obj, &phy_status);
209         #endif
210 
211         #if defined(__USE_RTL8211) && __USE_RTL8211
212         rtl8211_get_phy_status(phy->bus->hw_obj, &phy_status);
213         #endif
214 
215         #if defined(__USE_RTL8201) && __USE_RTL8201 && !defined(BSP_USING_ETH1)
216         rtl8201_get_phy_status(phy->bus->hw_obj, &phy_status);
217         #endif
218     }
219 
220 #if defined(HPM_ENET1_BASE)
221     if (phy->bus->hw_obj == HPM_ENET1)
222     {
223         #if defined(__USE_DP83848) && __USE_DP83848
224         dp83848_get_phy_status(phy->bus->hw_obj, &phy_status);
225         #endif
226 
227         #if defined(__USE_RTL8201) && __USE_RTL8201
228         rtl8201_get_phy_status(phy->bus->hw_obj, &phy_status);
229         #endif
230 
231         #if defined(__USE_LAN8720) && __USE_LAN8720
232         lan8720_get_phy_status(phy->bus->hw_obj, &phy_status);
233         #endif
234     }
235 #endif
236 
237     *status = phy_status.enet_phy_link;
238 
239     return PHY_STATUS_OK;
240 }
241 
phy_get_link_speed_duplex(rt_phy_t * phy,rt_uint32_t * speed,rt_uint32_t * duplex)242 static rt_phy_status phy_get_link_speed_duplex(rt_phy_t *phy, rt_uint32_t *speed, rt_uint32_t *duplex)
243 {
244     enet_phy_status_t phy_status;
245 
246     if (phy->bus->hw_obj == HPM_ENET0)
247     {
248         #if defined(__USE_DP83867) && __USE_DP83867
249         dp83867_get_phy_status(phy->bus->hw_obj, &phy_status);
250         #endif
251 
252         #if defined(__USE_RTL8211) && __USE_RTL8211
253         rtl8211_get_phy_status(phy->bus->hw_obj, &phy_status);
254         #endif
255 
256         #if defined(__USE_RTL8201) && __USE_RTL8201 && !defined(BSP_USING_ETH1)
257         rtl8201_get_phy_status(phy->bus->hw_obj, &phy_status);
258         #endif
259     }
260 
261 #if defined(HPM_ENET1_BASE)
262     if (phy->bus->hw_obj == HPM_ENET1)
263     {
264         #if defined(__USE_DP83848) && __USE_DP83848
265         dp83848_get_phy_status(phy->bus->hw_obj, &phy_status);
266         #endif
267 
268         #if defined(__USE_RTL8201) && __USE_RTL8201
269         rtl8201_get_phy_status(phy->bus->hw_obj, &phy_status);
270         #endif
271 
272         #if defined(__USE_LAN8720) && __USE_LAN8720
273         lan8720_get_phy_status(phy->bus->hw_obj, &phy_status);
274         #endif
275     }
276 #endif
277 
278     *speed  = phy_status.enet_phy_speed;
279     *duplex = phy_status.enet_phy_duplex;
280 
281     return PHY_STATUS_OK;
282 }
283 
phy_poll_status(void * parameter)284 static void phy_poll_status(void *parameter)
285 {
286     int ret;
287     phy_info_t phy_info;
288     rt_bool_t status;
289     rt_device_t dev;
290     rt_phy_msg_t msg;
291     rt_uint32_t speed, duplex;
292     phy_device_t *phy_dev;
293     struct eth_device* eth_dev;
294     char const *ps[] = {"10Mbps", "100Mbps", "1000Mbps"};
295     enet_line_speed_t line_speed[] = {enet_line_speed_10mbps, enet_line_speed_100mbps, enet_line_speed_1000mbps};
296 
297     eth_phy_monitor_handle_t *phy_monitor_handle = (eth_phy_monitor_handle_t *)parameter;
298 
299     for (uint32_t i = 0; i < phy_monitor_handle->phy_handle_cnt; i++)
300     {
301         eth_dev = phy_monitor_handle->phy_handle[i]->eth_dev;
302         phy_dev = phy_monitor_handle->phy_handle[i]->phy_dev;
303 
304         phy_dev->phy.ops->get_link_status(&phy_dev->phy, &status);
305 
306         if (status)
307         {
308             phy_dev->phy.ops->get_link_speed_duplex(&phy_dev->phy, &phy_info.phy_speed, &phy_info.phy_duplex);
309 
310             ret = memcmp(&phy_dev->phy_info, &phy_info, sizeof(phy_info_t));
311             if (ret != 0)
312             {
313                 memcpy(&phy_dev->phy_info, &phy_info, sizeof(phy_info_t));
314             }
315         }
316 
317         if (phy_dev->phy_link != status)
318         {
319             phy_dev->phy_link = status ? PHY_LINK_UP : PHY_LINK_DOWN;
320             eth_device_linkchange(eth_dev, status);
321             LOG_I("%s", phy_dev->phy.bus->hw_obj == HPM_ENET0 ? "ENET0" : "ENET1");
322             LOG_I("PHY Status: %s", status ? "Link up" : "Link down\n");
323             if (status == PHY_LINK_UP)
324             {
325                 LOG_I("PHY Speed: %s", ps[phy_dev->phy_info.phy_speed]);
326                 LOG_I("PHY Duplex: %s\n", phy_dev->phy_info.phy_duplex & PHY_FULL_DUPLEX ? "full duplex" : "half duplex");
327                 enet_set_line_speed(phy_monitor_handle->phy_handle[i]->instance, line_speed[phy_dev->phy_info.phy_speed]);
328                 enet_set_duplex_mode(phy_monitor_handle->phy_handle[i]->instance, phy_dev->phy_info.phy_duplex);
329             }
330         }
331     }
332 }
333 
phy_detection(void * parameter)334 static void phy_detection(void *parameter)
335 {
336     phy_device_t *phy_dev = (phy_device_t *)parameter;
337 
338     if (phy_dev->phy.ops->init(phy_dev->phy.bus->hw_obj, 0, PHY_MDIO_CSR_CLK_FREQ) != PHY_STATUS_OK)
339     {
340         LOG_E("No any PHY device is detected! Please check your hardware!\n");
341     }
342 
343     return;
344 
345 }
346 
phy_monitor_thread_entry(void * args)347 static void phy_monitor_thread_entry(void *args)
348 {
349     rt_timer_t phy_status_timer;
350 
351     eth_phy_monitor_handle_t *phy_monitor_handle = (eth_phy_monitor_handle_t *)args;
352 
353     for (uint32_t i = 0; i < phy_monitor_handle->phy_handle_cnt; i++)
354     {
355         LOG_D("Detect a PHY%d\n", i);
356         phy_detection(phy_monitor_handle->phy_handle[i]->phy_dev);
357     }
358 
359     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);
360 
361     if (!phy_status_timer || rt_timer_start(phy_status_timer) != RT_EOK)
362     {
363         LOG_E("Failed to start link change detection timer\n");
364     }
365 }
366 
phy_device_register(void)367 int phy_device_register(void)
368 {
369     rt_err_t err = -RT_ERROR;
370     rt_thread_t thread_phy_monitor;
371 
372     /* Set ops for PHY */
373     phy_ops.init = phy_init;
374     phy_ops.get_link_status = phy_get_link_status;
375     phy_ops.get_link_speed_duplex = phy_get_link_speed_duplex;
376 
377     for (uint32_t i = 0; i < ARRAY_SIZE(s_gphys); i++)
378     {
379         /* Set PHY address */
380         s_gphys[i]->phy_dev->phy.addr = 0xffff;
381 
382         /* Set MIDO bus */
383         s_gphys[i]->mdio_bus->hw_obj     = s_gphys[i]->instance;
384         s_gphys[i]->mdio_bus->name       = s_gphys[i]->mdio_name;
385         s_gphys[i]->mdio_bus->ops->read  = phy_read;
386         s_gphys[i]->mdio_bus->ops->write = phy_write;
387         s_gphys[i]->phy_dev->phy.bus     = s_gphys[i]->mdio_bus;
388         s_gphys[i]->phy_dev->phy.ops     = &phy_ops;
389 
390         rt_hw_phy_register(&s_gphys[i]->phy_dev->phy, NULL);
391     }
392 
393     /* Start PHY monitor */
394     thread_phy_monitor = rt_thread_create("PHY Monitor", phy_monitor_thread_entry, &phy_monitor_handle, 1024, RT_THREAD_PRIORITY_MAX - 2, 2);
395 
396     if (thread_phy_monitor != RT_NULL)
397     {
398         rt_thread_startup(thread_phy_monitor);
399     }
400     else
401     {
402         err = -RT_ERROR;
403     }
404 
405     return err;
406 }
407 INIT_PREV_EXPORT(phy_device_register);
408 #endif /* RT_USING_PHY */
409