1
2 /*
3 * Copyright (c) 2006-2023, RT-Thread Development Team
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date Author Notes
9 * 2020-09-29 WangQiang the first version
10 *
11 */
12
13 #include <rtthread.h>
14
15 #ifdef BSP_USING_PHY
16
17 #define LOG_TAG "drv.mdio"
18 #include <drv_log.h>
19
20 #include <rtdevice.h>
21 #include "drv_mdio.h"
22
23
24
25 /*! @brief Defines the timeout macro. */
26 #define PHY_TIMEOUT_COUNT 0x3FFFFFFU
27
28 /*!
29 * @brief Get the ENET instance from peripheral base address.
30 *
31 * @param base ENET peripheral base address.
32 * @return ENET instance.
33 */
34 extern uint32_t ENET_GetInstance(ENET_Type *base);
35
36 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
37 /*! @brief Pointers to enet clocks for each instance. */
38 extern const clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
39 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
40
rt_hw_mdio_init(void * bus,rt_uint32_t src_clock_hz)41 static rt_bool_t rt_hw_mdio_init(void *bus, rt_uint32_t src_clock_hz)
42 {
43 struct rt_mdio_bus *bus_obj = (struct rt_mdio_bus *)bus;
44 uint32_t instance = ENET_GetInstance((ENET_Type *)(bus_obj->hw_obj));
45 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
46 /* Set SMI first. */
47 CLOCK_EnableClock(s_enetClock[instance]);
48 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
49 ENET_SetSMI((ENET_Type *)(bus_obj->hw_obj), src_clock_hz, RT_FALSE);
50
51 return RT_TRUE;
52 }
53
rt_hw_mdio_read(void * bus,rt_uint32_t addr,rt_uint32_t reg,void * data,rt_uint32_t size)54 static rt_ssize_t rt_hw_mdio_read(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
55 {
56 RT_ASSERT(data);
57 struct rt_mdio_bus *bus_obj = (struct rt_mdio_bus *)bus;
58
59 rt_uint32_t counter;
60 rt_uint32_t *data_ptr = (rt_uint32_t *)data;
61
62 if (4 != size)
63 {
64 return 0;
65 }
66
67 /* Clear the MII interrupt event. */
68 ENET_ClearInterruptStatus((ENET_Type *)(bus_obj->hw_obj), ENET_EIR_MII_MASK);
69
70 /* Starts a SMI read command operation. */
71 ENET_StartSMIRead((ENET_Type *)(bus_obj->hw_obj), addr, reg, kENET_MiiReadValidFrame);
72
73 /* Wait for MII complete. */
74 for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
75 {
76 if (ENET_GetInterruptStatus((ENET_Type *)(bus_obj->hw_obj)) & ENET_EIR_MII_MASK)
77 {
78 break;
79 }
80 }
81
82 /* Check for timeout. */
83 if (!counter)
84 {
85 // return kStatus_PHY_SMIVisitTimeout;
86 return 0;
87 }
88
89 /* Get data from MII register. */
90 *data_ptr = ENET_ReadSMIData((ENET_Type *)(bus_obj->hw_obj));
91
92 /* Clear MII interrupt event. */
93 ENET_ClearInterruptStatus((ENET_Type *)bus_obj->hw_obj, ENET_EIR_MII_MASK);
94
95 return 4;
96 }
97
98
rt_hw_mdio_write(void * bus,rt_uint32_t addr,rt_uint32_t reg,void * data,rt_uint32_t size)99 static rt_ssize_t rt_hw_mdio_write(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
100 {
101 struct rt_mdio_bus *bus_obj = (struct rt_mdio_bus *)bus;
102 uint32_t counter;
103 rt_uint32_t *data_ptr = (rt_uint32_t *)data;
104
105 if (4 != size)
106 {
107 return 0;
108 }
109
110 /* Clear the SMI interrupt event. */
111 ENET_ClearInterruptStatus((ENET_Type *)(bus_obj->hw_obj), ENET_EIR_MII_MASK);
112
113 /* Starts a SMI write command. */
114 ENET_StartSMIWrite((ENET_Type *)(bus_obj->hw_obj), addr, reg, kENET_MiiWriteValidFrame, *data_ptr);
115
116 /* Wait for SMI complete. */
117 for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
118 {
119 if (ENET_GetInterruptStatus((ENET_Type *)(bus_obj->hw_obj)) & ENET_EIR_MII_MASK)
120 {
121 break;
122 }
123 }
124
125 /* Check for timeout. */
126 if (!counter)
127 {
128 return 0;
129 }
130
131 /* Clear MII interrupt event. */
132 ENET_ClearInterruptStatus((ENET_Type *)(bus_obj->hw_obj), ENET_EIR_MII_MASK);
133
134 return size;
135 }
136
137 static struct rt_mdio_bus_ops imxrt_mdio_ops =
138 {
139 .init = rt_hw_mdio_init,
140 .read = rt_hw_mdio_read,
141 .write = rt_hw_mdio_write,
142 .uninit = RT_NULL,
143 };
144
145 static rt_mdio_t mdio_bus;
146
rt_hw_mdio_register(void * hw_obj,char * name)147 rt_mdio_t *rt_hw_mdio_register(void *hw_obj, char *name)
148 {
149 mdio_bus.hw_obj = hw_obj;
150 mdio_bus.name = name;
151 mdio_bus.ops = &imxrt_mdio_ops;
152 return &mdio_bus;
153 }
154
rt_hw_mdio_get(void)155 rt_mdio_t *rt_hw_mdio_get(void)
156 {
157 return &mdio_bus;
158 }
159
160 #endif
161