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