dm9161_driver.c
Go to the documentation of this file.
1 /**
2  * @file dm9161_driver.c
3  * @brief DM9161 Ethernet PHY transceiver
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL NIC_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/net.h"
35 #include "debug.h"
36 
37 
38 /**
39  * @brief DM9161 Ethernet PHY driver
40  **/
41 
43 {
44  dm9161Init,
45  dm9161Tick,
49 };
50 
51 
52 /**
53  * @brief DM9161 PHY transceiver initialization
54  * @param[in] interface Underlying network interface
55  * @return Error code
56  **/
57 
59 {
60  volatile uint32_t status;
61 
62  //Debug message
63  TRACE_INFO("Initializing DM9161...\r\n");
64 
65  //Initialize external interrupt line driver
66  if(interface->extIntDriver != NULL)
67  interface->extIntDriver->init();
68 
69  //Reset PHY transceiver
71  //Wait for the reset to complete
72  while(dm9161ReadPhyReg(interface, DM9161_PHY_REG_BMCR) & BMCR_RESET);
73 
74  //Dump PHY registers for debugging purpose
75  dm9161DumpPhyReg(interface);
76 
77  //The PHY will generate interrupts when link status changes are detected
79 
80  //Force the TCP/IP stack to poll the link state at startup
81  interface->phyEvent = TRUE;
82  //Notify the TCP/IP stack of the event
84 
85  //Successful initialization
86  return NO_ERROR;
87 }
88 
89 
90 /**
91  * @brief DM9161 timer handler
92  * @param[in] interface Underlying network interface
93  **/
94 
95 void dm9161Tick(NetInterface *interface)
96 {
97  uint16_t value;
98  bool_t linkState;
99 
100  //No external interrupt line driver?
101  if(interface->extIntDriver == NULL)
102  {
103  //Read basic status register
105  //Retrieve current link state
106  linkState = (value & BMSR_LINK_STATUS) ? TRUE : FALSE;
107 
108  //Link up event?
109  if(linkState && !interface->linkState)
110  {
111  //Set event flag
112  interface->phyEvent = TRUE;
113  //Notify the TCP/IP stack of the event
115  }
116  //Link down event?
117  else if(!linkState && interface->linkState)
118  {
119  //Set event flag
120  interface->phyEvent = TRUE;
121  //Notify the TCP/IP stack of the event
123  }
124  }
125 }
126 
127 
128 /**
129  * @brief Enable interrupts
130  * @param[in] interface Underlying network interface
131  **/
132 
134 {
135  //Enable PHY transceiver interrupts
136  if(interface->extIntDriver != NULL)
137  interface->extIntDriver->enableIrq();
138 }
139 
140 
141 /**
142  * @brief Disable interrupts
143  * @param[in] interface Underlying network interface
144  **/
145 
147 {
148  //Disable PHY transceiver interrupts
149  if(interface->extIntDriver != NULL)
150  interface->extIntDriver->disableIrq();
151 }
152 
153 
154 /**
155  * @brief DM9161 event handler
156  * @param[in] interface Underlying network interface
157  **/
158 
160 {
161  uint16_t value;
162  bool_t end;
163 
164  //Read status register to acknowledge the interrupt
166 
167  //Link status change?
169  {
170  //Any link failure condition is latched in the BMSR register... Reading
171  //the register twice will always return the actual link status
174 
175  //Link is up?
176  if(value & BMSR_LINK_STATUS)
177  {
178  //Wait for the auto-negotiation to complete
179  do
180  {
181  //Read DSCSR register
183 
184  //Check current state
185  switch(value & DSCSR_ANMB_MASK)
186  {
187  //Auto-negotiation is still in progress?
192  end = FALSE;
193  break;
194  //Auto-negotiation is complete?
195  default:
196  end = TRUE;
197  break;
198  }
199 
200  //Check loop condition variable
201  } while(!end);
202 
203  //Read DSCSR register
205 
206  //Check current operation mode
207  if(value & DSCSR_10HDX)
208  {
209  //10BASE-T half-duplex
210  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
211  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
212  }
213  else if(value & DSCSR_10FDX)
214  {
215  //10BASE-T full-duplex
216  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
217  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
218  }
219  else if(value & DSCSR_100HDX)
220  {
221  //100BASE-TX half-duplex
222  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
223  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
224  }
225  else if(value & DSCSR_100FDX)
226  {
227  //100BASE-TX full-duplex
228  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
229  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
230  }
231  else
232  {
233  //Debug message
234  TRACE_WARNING("Invalid Duplex mode\r\n");
235  }
236 
237  //Update link state
238  interface->linkState = TRUE;
239 
240  //Adjust MAC configuration parameters for proper operation
241  interface->nicDriver->updateMacConfig(interface);
242  }
243  else
244  {
245  //Update link state
246  interface->linkState = FALSE;
247  }
248 
249  //Process link state change event
250  nicNotifyLinkChange(interface);
251  }
252 }
253 
254 
255 /**
256  * @brief Write PHY register
257  * @param[in] interface Underlying network interface
258  * @param[in] address PHY register address
259  * @param[in] data Register value
260  **/
261 
262 void dm9161WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
263 {
264  uint8_t phyAddr;
265 
266  //Get the address of the PHY transceiver
267  if(interface->phyAddr < 32)
268  phyAddr = interface->phyAddr;
269  else
270  phyAddr = DM9161_PHY_ADDR;
271 
272  //Write the specified PHY register
273  interface->nicDriver->writePhyReg(phyAddr, address, data);
274 }
275 
276 
277 /**
278  * @brief Read PHY register
279  * @param[in] interface Underlying network interface
280  * @param[in] address PHY register address
281  * @return Register value
282  **/
283 
284 uint16_t dm9161ReadPhyReg(NetInterface *interface, uint8_t address)
285 {
286  uint8_t phyAddr;
287 
288  //Get the address of the PHY transceiver
289  if(interface->phyAddr < 32)
290  phyAddr = interface->phyAddr;
291  else
292  phyAddr = DM9161_PHY_ADDR;
293 
294  //Read the specified PHY register
295  return interface->nicDriver->readPhyReg(phyAddr, address);
296 }
297 
298 
299 /**
300  * @brief Dump PHY registers for debugging purpose
301  * @param[in] interface Underlying network interface
302  **/
303 
305 {
306  uint8_t i;
307 
308  //Loop through PHY registers
309  for(i = 0; i < 32; i++)
310  {
311  //Display current PHY register
312  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, dm9161ReadPhyReg(interface, i));
313  }
314 
315  //Terminate with a line feed
316  TRACE_DEBUG("\r\n");
317 }
#define DSCSR_100FDX
#define DSCSR_ANMB_MASK
void nicNotifyLinkChange(NetInterface *interface)
Process link state change event.
Definition: nic.c:298
#define DM9161_PHY_REG_BMCR
Definition: dm9161_driver.h:43
#define MDINTR_INTR_MASK
DM9161 Ethernet PHY transceiver.
TCP/IP stack core.
#define DSCSR_100HDX
Debugging facilities.
const PhyDriver dm9161PhyDriver
DM9161 Ethernet PHY driver.
Definition: dm9161_driver.c:42
#define DSCSR_10HDX
#define BMSR_LINK_STATUS
Definition: ar8031_driver.h:95
#define DM9161_PHY_REG_BMSR
Definition: dm9161_driver.h:44
#define DSCSR_ANMB_ACK_MATCH
#define MDINTR_LINK_MASK
#define TRUE
Definition: os_port.h:48
PHY driver.
Definition: nic.h:196
#define DSCSR_10FDX
void dm9161DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
#define DSCSR_ANMB_ABILITY_MATCH
error_t dm9161Init(NetInterface *interface)
DM9161 PHY transceiver initialization.
Definition: dm9161_driver.c:58
void dm9161Tick(NetInterface *interface)
DM9161 timer handler.
Definition: dm9161_driver.c:95
#define BMCR_RESET
Definition: ar8031_driver.h:71
uint16_t dm9161ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
void dm9161EnableIrq(NetInterface *interface)
Enable interrupts.
#define TRACE_INFO(...)
Definition: debug.h:86
#define DSCSR_ANMB_CONSIST_MATCH
Success.
Definition: error.h:42
Ipv6Addr address
OsEvent netEvent
Definition: net.c:72
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
error_t
Error codes.
Definition: error.h:40
#define TRACE_WARNING(...)
Definition: debug.h:78
void dm9161WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
uint8_t data[]
Definition: dtls_misc.h:167
#define NetInterface
Definition: net.h:34
uint8_t value[]
Definition: dtls_misc.h:141
#define MDINTR_LINK_CHANGE
#define DM9161_PHY_REG_DSCSR
Definition: dm9161_driver.h:51
#define DM9161_PHY_REG_MDINTR
Definition: dm9161_driver.h:53
#define DM9161_PHY_ADDR
Definition: dm9161_driver.h:37
void dm9161EventHandler(NetInterface *interface)
DM9161 event handler.
#define FALSE
Definition: os_port.h:44
int bool_t
Definition: compiler_port.h:47
#define DSCSR_ANMB_SIGNAL_LINK_READY
void dm9161DisableIrq(NetInterface *interface)
Disable interrupts.
#define TRACE_DEBUG(...)
Definition: debug.h:98