1+ /* 
2+  * Copyright 2025 Planet Innovation 
3+  * All rights reserved. 
4+  * 
5+  * Based on NXP RTL8211F driver structure and TI DP83867 specifications. 
6+  * SPDX-License-Identifier: BSD-3-Clause 
7+  */ 
8+ 
9+ #include  "fsl_phydp83867.h" 
10+ 
11+ /******************************************************************************* 
12+  * Definitions 
13+  ******************************************************************************/ 
14+ 
15+ /*! @brief Defines the PHY DP83867 vendor defined registers. */ 
16+ #define  PHY_PHYSTS_REG           0x11U /*!< The PHY Status register. */ 
17+ 
18+ /*! @brief Defines the PHY DP83867 ID number. */ 
19+ #define  PHY_CONTROL_ID1          0x2000U /*!< The PHY ID1 (upper 16 bits). */ 
20+ #define  PHY_CONTROL_ID2          0xA231U /*!< The PHY ID2 (lower 16 bits). */ 
21+ #define  PHY_FULL_ID              0x2000A231U /*!< Full PHY ID. */ 
22+ 
23+ /*! @brief Defines the mask flag in PHYSTS register. */ 
24+ #define  PHY_PHYSTS_LINKSTATUS_MASK   0x0400U /*!< The PHY link status mask. */ 
25+ #define  PHY_PHYSTS_LINKSPEED_MASK    0xC000U /*!< The PHY link speed mask. */ 
26+ #define  PHY_PHYSTS_LINKDUPLEX_MASK   0x2000U /*!< The PHY link duplex mask. */ 
27+ #define  PHY_PHYSTS_LINKSPEED_SHIFT   14U     /*!< The link speed shift */ 
28+ 
29+ /*! @brief Link speed values from PHYSTS register. */ 
30+ #define  PHY_PHYSTS_LINKSPEED_10M     0U /*!< 10M link speed. */ 
31+ #define  PHY_PHYSTS_LINKSPEED_100M    1U /*!< 100M link speed. */ 
32+ #define  PHY_PHYSTS_LINKSPEED_1000M   2U /*!< 1000M link speed. */ 
33+ 
34+ /*! @brief Defines the timeout macro. */ 
35+ #define  PHY_READID_TIMEOUT_COUNT     1000U
36+ 
37+ /******************************************************************************* 
38+  * Prototypes 
39+  ******************************************************************************/ 
40+ 
41+ /******************************************************************************* 
42+  * Variables 
43+  ******************************************************************************/ 
44+ 
45+ const  phy_operations_t  phydp83867_ops  =  {.phyInit  =  PHY_DP83867_Init ,
46+                                          .phyWrite  =  PHY_DP83867_Write ,
47+                                          .phyRead  =  PHY_DP83867_Read ,
48+                                          .getAutoNegoStatus  =  PHY_DP83867_GetAutoNegotiationStatus ,
49+                                          .getLinkStatus  =  PHY_DP83867_GetLinkStatus ,
50+                                          .getLinkSpeedDuplex  =  PHY_DP83867_GetLinkSpeedDuplex ,
51+                                          .setLinkSpeedDuplex  =  PHY_DP83867_SetLinkSpeedDuplex ,
52+                                          .enableLoopback  =  PHY_DP83867_EnableLoopback };
53+ 
54+ /******************************************************************************* 
55+  * Code 
56+  ******************************************************************************/ 
57+ 
58+ status_t  PHY_DP83867_Init (phy_handle_t  * handle , const  phy_config_t  * config ) {
59+     uint32_t  counter  =  PHY_READID_TIMEOUT_COUNT ;
60+     status_t  result ;
61+     uint32_t  regValue  =  0U ;
62+ 
63+ 
64+     /* Init MDIO interface. */ 
65+     MDIO_Init (handle -> mdioHandle );
66+ 
67+     /* Assign phy address. */ 
68+     handle -> phyAddr  =  config -> phyAddr ;
69+ 
70+ 
71+     /* Check PHY ID. */ 
72+     do 
73+     {
74+         result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_ID1_REG , & regValue );
75+         if  (result  !=  kStatus_Success ) {
76+             return  result ;
77+         }
78+         counter -- ;
79+     } while  ((regValue  !=  PHY_CONTROL_ID1 ) &&  (counter  !=  0U ));
80+ 
81+     if  (counter  ==  0U ) {
82+         return  kStatus_Fail ;
83+     }
84+ 
85+ 
86+     /* Reset PHY. */ 
87+     result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , PHY_BCTL_RESET_MASK );
88+     if  (result  !=  kStatus_Success ) {
89+         return  result ;
90+     }
91+ 
92+ 
93+     /* Wait for reset to complete */ 
94+     counter  =  PHY_READID_TIMEOUT_COUNT ;
95+     do  {
96+         result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , & regValue );
97+         if  (result  !=  kStatus_Success ) {
98+             return  result ;
99+         }
100+         counter -- ;
101+     } while  ((regValue  &  PHY_BCTL_RESET_MASK ) &&  (counter  !=  0U ));
102+ 
103+     if  (counter  ==  0U ) {
104+         return  kStatus_Fail ;
105+     }
106+ 
107+ 
108+     if  (config -> autoNeg ) {
109+         /* Set the auto-negotiation. */ 
110+         result  = 
111+             MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_AUTONEG_ADVERTISE_REG ,
112+                 PHY_100BASETX_FULLDUPLEX_MASK  | PHY_100BASETX_HALFDUPLEX_MASK  | PHY_10BASETX_FULLDUPLEX_MASK  |
113+                 PHY_10BASETX_HALFDUPLEX_MASK  | PHY_IEEE802_3_SELECTOR_MASK );
114+         if  (result  ==  kStatus_Success ) {
115+             result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_1000BASET_CONTROL_REG ,
116+                 PHY_1000BASET_FULLDUPLEX_MASK );
117+             if  (result  ==  kStatus_Success ) {
118+                 result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , & regValue );
119+                 if  (result  ==  kStatus_Success ) {
120+                     result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG ,
121+                         (regValue  | PHY_BCTL_AUTONEG_MASK  | PHY_BCTL_RESTART_AUTONEG_MASK ));
122+                 }
123+             }
124+         }
125+     } else  {
126+         /* Disable isolate mode */ 
127+         result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , & regValue );
128+         if  (result  !=  kStatus_Success ) {
129+             return  result ;
130+         }
131+         regValue  &= ~PHY_BCTL_ISOLATE_MASK ;
132+         result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , regValue );
133+         if  (result  !=  kStatus_Success ) {
134+             return  result ;
135+         }
136+ 
137+         /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ 
138+         result  =  PHY_DP83867_SetLinkSpeedDuplex (handle , config -> speed , config -> duplex );
139+     }
140+     
141+     
142+     return  result ;
143+ }
144+ 
145+ status_t  PHY_DP83867_Write (phy_handle_t  * handle , uint32_t  phyReg , uint32_t  data ) {
146+     return  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , phyReg , data );
147+ }
148+ 
149+ status_t  PHY_DP83867_Read (phy_handle_t  * handle , uint32_t  phyReg , uint32_t  * dataPtr ) {
150+     return  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , phyReg , dataPtr );
151+ }
152+ 
153+ status_t  PHY_DP83867_GetAutoNegotiationStatus (phy_handle_t  * handle , bool  * status ) {
154+     assert (status );
155+ 
156+     status_t  result ;
157+     uint32_t  regValue ;
158+ 
159+     * status  =  false;
160+ 
161+     /* Check auto negotiation complete. */ 
162+     result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_BASICSTATUS_REG , & regValue );
163+     if  (result  ==  kStatus_Success ) {
164+         if  ((regValue  &  PHY_BSTATUS_AUTONEGCOMP_MASK ) !=  0U ) {
165+             * status  =  true;
166+         }
167+     }
168+     return  result ;
169+ }
170+ 
171+ status_t  PHY_DP83867_GetLinkStatus (phy_handle_t  * handle , bool  * status ) {
172+     assert (status );
173+ 
174+     status_t  result ;
175+     uint32_t  regValue ;
176+ 
177+     /* Read the PHY Status register. */ 
178+     result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_PHYSTS_REG , & regValue );
179+     if  (result  ==  kStatus_Success ) {
180+         if  ((PHY_PHYSTS_LINKSTATUS_MASK  &  regValue ) !=  0U ) {
181+             /* Link up. */ 
182+             * status  =  true;
183+         } else  {
184+             /* Link down. */ 
185+             * status  =  false;
186+         }
187+     }
188+     return  result ;
189+ }
190+ 
191+ status_t  PHY_DP83867_GetLinkSpeedDuplex (phy_handle_t  * handle , phy_speed_t  * speed , phy_duplex_t  * duplex ) {
192+     assert (!((speed  ==  NULL ) &&  (duplex  ==  NULL )));
193+ 
194+     status_t  result ;
195+     uint32_t  regValue ;
196+ 
197+     /* Read the status register. */ 
198+     result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_PHYSTS_REG , & regValue );
199+     if  (result  ==  kStatus_Success ) {
200+         if  (speed  !=  NULL ) {
201+             switch  ((regValue  &  PHY_PHYSTS_LINKSPEED_MASK ) >> PHY_PHYSTS_LINKSPEED_SHIFT )
202+             {
203+                 case  PHY_PHYSTS_LINKSPEED_10M :
204+                     * speed  =  kPHY_Speed10M ;
205+                     break ;
206+                 case  PHY_PHYSTS_LINKSPEED_100M :
207+                     * speed  =  kPHY_Speed100M ;
208+                     break ;
209+                 case  PHY_PHYSTS_LINKSPEED_1000M :
210+                     * speed  =  kPHY_Speed1000M ;
211+                     break ;
212+                 default :
213+                     * speed  =  kPHY_Speed10M ;
214+                     break ;
215+             }
216+         }
217+ 
218+         if  (duplex  !=  NULL ) {
219+             if  ((regValue  &  PHY_PHYSTS_LINKDUPLEX_MASK ) !=  0U ) {
220+                 * duplex  =  kPHY_FullDuplex ;
221+             } else  {
222+                 * duplex  =  kPHY_HalfDuplex ;
223+             }
224+         }
225+     }
226+     return  result ;
227+ }
228+ 
229+ status_t  PHY_DP83867_SetLinkSpeedDuplex (phy_handle_t  * handle , phy_speed_t  speed , phy_duplex_t  duplex ) {
230+     status_t  result ;
231+     uint32_t  regValue ;
232+ 
233+     result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , & regValue );
234+     if  (result  ==  kStatus_Success ) {
235+         /* Disable the auto-negotiation and set according to user-defined configuration. */ 
236+         regValue  &= ~PHY_BCTL_AUTONEG_MASK ;
237+         if  (speed  ==  kPHY_Speed1000M ) {
238+             regValue  &= ~PHY_BCTL_SPEED0_MASK ;
239+             regValue  |= PHY_BCTL_SPEED1_MASK ;
240+         } else  if  (speed  ==  kPHY_Speed100M ) {
241+             regValue  |= PHY_BCTL_SPEED0_MASK ;
242+             regValue  &= ~PHY_BCTL_SPEED1_MASK ;
243+         } else  {
244+             regValue  &= ~PHY_BCTL_SPEED0_MASK ;
245+             regValue  &= ~PHY_BCTL_SPEED1_MASK ;
246+         }
247+         if  (duplex  ==  kPHY_FullDuplex ) {
248+             regValue  |= PHY_BCTL_DUPLEX_MASK ;
249+         } else  {
250+             regValue  &= ~PHY_BCTL_DUPLEX_MASK ;
251+         }
252+         result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , regValue );
253+     }
254+     return  result ;
255+ }
256+ 
257+ status_t  PHY_DP83867_EnableLoopback (phy_handle_t  * handle , phy_loop_t  mode , phy_speed_t  speed , bool  enable ) {
258+     /* This PHY only supports local loopback. */ 
259+     assert (mode  ==  kPHY_LocalLoop );
260+ 
261+     status_t  result ;
262+     uint32_t  regValue ;
263+ 
264+     /* Set the loop mode. */ 
265+     if  (enable ) {
266+         if  (speed  ==  kPHY_Speed1000M ) {
267+             regValue  =  PHY_BCTL_SPEED1_MASK  | PHY_BCTL_DUPLEX_MASK  | PHY_BCTL_LOOP_MASK ;
268+         } else  if  (speed  ==  kPHY_Speed100M ) {
269+             regValue  =  PHY_BCTL_SPEED0_MASK  | PHY_BCTL_DUPLEX_MASK  | PHY_BCTL_LOOP_MASK ;
270+         } else  {
271+             regValue  =  PHY_BCTL_DUPLEX_MASK  | PHY_BCTL_LOOP_MASK ;
272+         }
273+         result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , regValue );
274+     } else  {
275+         /* First read the current status in control register. */ 
276+         result  =  MDIO_Read (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG , & regValue );
277+         if  (result  ==  kStatus_Success ) {
278+             regValue  &= ~PHY_BCTL_LOOP_MASK ;
279+             result  =  MDIO_Write (handle -> mdioHandle , handle -> phyAddr , PHY_BASICCONTROL_REG ,
280+                 (regValue  | PHY_BCTL_RESTART_AUTONEG_MASK ));
281+         }
282+     }
283+     return  result ;
284+ }
0 commit comments