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 = ð0_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 = ð1_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 ð0_phy_handle,
75 #endif
76
77 #ifdef BSP_USING_ETH1
78 ð1_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