]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.c
1579863fe90679fac89d9d6801d54afa0bf3d487
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / ksz8851snl / ksz8851snl.c
1 /**\r
2  *\r
3  * \file\r
4  *\r
5  * \brief KS8851SNL driver for SAM.\r
6  *\r
7  * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.\r
8  *\r
9  * \asf_license_start\r
10  *\r
11  * \page License\r
12  *\r
13  * Redistribution and use in source and binary forms, with or without\r
14  * modification, are permitted provided that the following conditions are met:\r
15  *\r
16  * 1. Redistributions of source code must retain the above copyright notice,\r
17  *    this list of conditions and the following disclaimer.\r
18  *\r
19  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
20  *    this list of conditions and the following disclaimer in the documentation\r
21  *    and/or other materials provided with the distribution.\r
22  *\r
23  * 3. The name of Atmel may not be used to endorse or promote products derived\r
24  *    from this software without specific prior written permission.\r
25  *\r
26  * 4. This software may only be redistributed and used in connection with an\r
27  *    Atmel microcontroller product.\r
28  *\r
29  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED\r
30  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
32  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR\r
33  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
38  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
39  * POSSIBILITY OF SUCH DAMAGE.\r
40  *\r
41  * \asf_license_stop\r
42  *\r
43  */\r
44 /*\r
45  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>\r
46  */\r
47 \r
48 /* FreeRTOS includes. */\r
49 #include "FreeRTOS.h"\r
50 #include "task.h"\r
51 \r
52 #include "spi_master.h"\r
53 #include "ksz8851snl.h"\r
54 #include "ksz8851snl_reg.h"\r
55 #include "delay.h"\r
56 #include "pio.h"\r
57 #include "pio_handler.h"\r
58 #include "pdc.h"\r
59 #include "conf_eth.h"\r
60 \r
61 /* Clock polarity. */\r
62 #define SPI_CLK_POLARITY 0\r
63 \r
64 /* Clock phase. */\r
65 #define SPI_CLK_PHASE 1\r
66 \r
67 /* SPI PDC register base. */\r
68 Pdc *g_p_spi_pdc = 0;\r
69 \r
70 int lUDPLoggingPrintf( const char *pcFormatString, ... );\r
71 \r
72 /* Temporary buffer for PDC reception. */\r
73 uint8_t tmpbuf[1536] __attribute__ ((aligned (16)));\r
74 \r
75 union {\r
76         uint64_t ul[2];\r
77         uint8_t uc[16];\r
78 } cmdBuf, respBuf;\r
79 \r
80 void dbg_add_line( const char *pcFormat, ... );\r
81 \r
82 static void spi_clear_ovres( void );\r
83 \r
84 /**\r
85  * \brief Read register content, set bitmask and write back to register.\r
86  *\r
87  * \param reg the register address to modify.\r
88  * \param bits_to_set bitmask to apply.\r
89  */\r
90 void ksz8851_reg_setbits(uint16_t reg, uint16_t bits_to_set)\r
91 {\r
92    uint16_t     temp;\r
93 \r
94    temp = ksz8851_reg_read(reg);\r
95    temp |= bits_to_set;\r
96    ksz8851_reg_write(reg, temp);\r
97 }\r
98 \r
99 /**\r
100  * \brief Read register content, clear bitmask and write back to register.\r
101  *\r
102  * \param reg the register address to modify.\r
103  * \param bits_to_set bitmask to apply.\r
104  */\r
105 void ksz8851_reg_clrbits(uint16_t reg, uint16_t bits_to_clr)\r
106 {\r
107    uint16_t     temp;\r
108 \r
109    temp = ksz8851_reg_read(reg);\r
110    temp &= ~(uint32_t) bits_to_clr;\r
111    ksz8851_reg_write(reg, temp);\r
112 }\r
113 \r
114 /**\r
115  * \brief Configure the INTN interrupt.\r
116  */\r
117 void configure_intn(void (*p_handler) (uint32_t, uint32_t))\r
118 {\r
119 //      gpio_configure_pin(KSZ8851SNL_INTN_GPIO, PIO_INPUT);\r
120 //      pio_set_input(PIOA, PIO_PA11_IDX, PIO_PULLUP);\r
121 \r
122         /* Configure PIO clock. */\r
123         pmc_enable_periph_clk(INTN_ID);\r
124 \r
125         /* Adjust PIO debounce filter parameters, uses 10 Hz filter. */\r
126         pio_set_debounce_filter(INTN_PIO, INTN_PIN_MSK, 10);\r
127 \r
128         /* Initialize PIO interrupt handlers, see PIO definition in board.h. */\r
129         pio_handler_set(INTN_PIO, INTN_ID, INTN_PIN_MSK,\r
130                 INTN_ATTR, p_handler);\r
131 \r
132         /* Enable NVIC interrupts. */\r
133         NVIC_SetPriority(INTN_IRQn, INT_PRIORITY_PIO);\r
134         NVIC_EnableIRQ((IRQn_Type)INTN_ID);\r
135 \r
136         /* Enable PIO interrupts. */\r
137         pio_enable_interrupt(INTN_PIO, INTN_PIN_MSK);\r
138 }\r
139 \r
140 /**\r
141  * \brief Read a register value.\r
142  *\r
143  * \param reg the register address to modify.\r
144  *\r
145  * \return the register value.\r
146  */\r
147 uint16_t ksz8851_reg_read(uint16_t reg)\r
148 {\r
149 pdc_packet_t g_pdc_spi_tx_packet;\r
150 pdc_packet_t g_pdc_spi_rx_packet;\r
151 uint16_t cmd = 0;\r
152 uint16_t res = 0;\r
153 int iTryCount = 3;\r
154 \r
155         while( iTryCount-- > 0 )\r
156         {\r
157         uint32_t ulStatus;\r
158 \r
159                 spi_clear_ovres();\r
160                 /* Move register address to cmd bits 9-2, make 32-bit address. */\r
161                 cmd = (reg << 2) & REG_ADDR_MASK;\r
162 \r
163                 /* Last 2 bits still under "don't care bits" handled with byte enable. */\r
164                 /* Select byte enable for command. */\r
165                 if (reg & 2) {\r
166                         /* Odd word address writes bytes 2 and 3 */\r
167                         cmd |= (0xc << 10);\r
168                 } else {\r
169                         /* Even word address write bytes 0 and 1 */\r
170                         cmd |= (0x3 << 10);\r
171                 }\r
172 \r
173                 /* Add command read code. */\r
174                 cmd |= CMD_READ;\r
175                 cmdBuf.uc[0] = cmd >> 8;\r
176                 cmdBuf.uc[1] = cmd & 0xff;\r
177                 cmdBuf.uc[2] = CONFIG_SPI_MASTER_DUMMY;\r
178                 cmdBuf.uc[3] = CONFIG_SPI_MASTER_DUMMY;\r
179 \r
180                 /* Prepare PDC transfer. */\r
181                 g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;\r
182                 g_pdc_spi_tx_packet.ul_size = 4;\r
183                 g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf;\r
184                 g_pdc_spi_rx_packet.ul_size = 4;\r
185                 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
186                 pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL);\r
187                 pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL);\r
188         gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);\r
189 \r
190         spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul );\r
191                 pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);\r
192                 for( ;; )\r
193                 {\r
194                         ulStatus = spi_read_status( KSZ8851SNL_SPI );\r
195                         if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 )\r
196                         {\r
197                                 break;\r
198                         }\r
199                 }\r
200                 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
201                 if( ( ulStatus & SPI_SR_OVRES ) == 0 )\r
202                 {\r
203                         break;\r
204                 }\r
205                 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
206                 lUDPLoggingPrintf( "ksz8851_reg_read: SPI_SR_OVRES\n" );\r
207         }\r
208 \r
209         res = (tmpbuf[3] << 8) | tmpbuf[2];\r
210         return res;\r
211 }\r
212 \r
213 /**\r
214  * \brief Write a register value.\r
215  *\r
216  * \param reg the register address to modify.\r
217  * \param wrdata the new register value.\r
218  */\r
219 void ksz8851_reg_write(uint16_t reg, uint16_t wrdata)\r
220 {\r
221 pdc_packet_t g_pdc_spi_tx_packet;\r
222 pdc_packet_t g_pdc_spi_rx_packet;\r
223 uint16_t cmd = 0;\r
224 int iTryCount = 3;\r
225 \r
226         while( iTryCount-- > 0 )\r
227         {\r
228         uint32_t ulStatus;\r
229 \r
230 \r
231                 spi_clear_ovres();\r
232                 /* Move register address to cmd bits 9-2, make 32-bit address. */\r
233                 cmd = (reg << 2) & REG_ADDR_MASK;\r
234 \r
235                 /* Last 2 bits still under "don't care bits" handled with byte enable. */\r
236                 /* Select byte enable for command. */\r
237                 if (reg & 2) {\r
238                         /* Odd word address writes bytes 2 and 3 */\r
239                         cmd |= (0xc << 10);\r
240                 } else {\r
241                         /* Even word address write bytes 0 and 1 */\r
242                         cmd |= (0x3 << 10);\r
243                 }\r
244 \r
245                 /* Add command write code. */\r
246                 cmd |= CMD_WRITE;\r
247                 cmdBuf.uc[0] = cmd >> 8;\r
248                 cmdBuf.uc[1] = cmd & 0xff;\r
249                 cmdBuf.uc[2] = wrdata & 0xff;\r
250                 cmdBuf.uc[3] = wrdata >> 8;\r
251 \r
252                 /* Prepare PDC transfer. */\r
253                 g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;\r
254                 g_pdc_spi_tx_packet.ul_size = 4;\r
255                 g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf;\r
256                 g_pdc_spi_rx_packet.ul_size = 4;\r
257                 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
258                 pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL);\r
259                 pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL);\r
260                 gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);\r
261 \r
262                 spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul );\r
263 \r
264                 pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);\r
265                 for( ;; )\r
266                 {\r
267                         ulStatus = spi_read_status( KSZ8851SNL_SPI );\r
268                         if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 )\r
269                         {\r
270                                 break;\r
271                         }\r
272                 }\r
273                 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
274                 if( ( ulStatus & SPI_SR_OVRES ) == 0 )\r
275                 {\r
276                         break;\r
277                 }\r
278                 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
279                 lUDPLoggingPrintf( "ksz8851_reg_write: SPI_SR_OVRES\n" );\r
280         }\r
281 }\r
282 \r
283 static void spi_clear_ovres( void )\r
284 {\r
285 volatile uint32_t rc;\r
286         rc = KSZ8851SNL_SPI->SPI_RDR;\r
287 \r
288         spi_read_status( KSZ8851SNL_SPI );\r
289 }\r
290 \r
291 /**\r
292  * \brief Read internal fifo buffer.\r
293  *\r
294  * \param buf the buffer to store the data from the fifo buffer.\r
295  * \param len the amount of data to read.\r
296  */\r
297 void ksz8851_fifo_read(uint8_t *buf, uint32_t len)\r
298 {\r
299         pdc_packet_t g_pdc_spi_tx_packet;\r
300         pdc_packet_t g_pdc_spi_rx_packet;\r
301         pdc_packet_t g_pdc_spi_tx_npacket;\r
302         pdc_packet_t g_pdc_spi_rx_npacket;\r
303 \r
304         memset( cmdBuf.uc, '\0', sizeof cmdBuf );\r
305         cmdBuf.uc[0] = FIFO_READ;\r
306         spi_clear_ovres();\r
307 \r
308         /* Prepare PDC transfer. */\r
309         g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;\r
310         g_pdc_spi_tx_packet.ul_size = 9;\r
311         g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc;\r
312         g_pdc_spi_rx_packet.ul_size = 9;\r
313 \r
314         g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf;\r
315         g_pdc_spi_tx_npacket.ul_size = len;\r
316         g_pdc_spi_rx_npacket.ul_addr = (uint32_t) buf;\r
317         g_pdc_spi_rx_npacket.ul_size = len;\r
318         pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
319         pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket);\r
320         pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket);\r
321 \r
322 spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_RXBUFF | SPI_IER_OVRES);\r
323 \r
324         pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);\r
325 }\r
326 \r
327 /**\r
328  * \brief Write internal fifo buffer.\r
329  *\r
330  * \param buf the buffer to send to the fifo buffer.\r
331  * \param ulActualLength the total amount of data to write.\r
332  * \param ulFIFOLength the size of the first pbuf to write from the pbuf chain.\r
333  */\r
334 void ksz8851_fifo_write(uint8_t *buf, uint32_t ulActualLength, uint32_t ulFIFOLength)\r
335 {\r
336         static uint8_t frameID = 0;\r
337 \r
338         pdc_packet_t g_pdc_spi_tx_packet;\r
339         pdc_packet_t g_pdc_spi_rx_packet;\r
340         pdc_packet_t g_pdc_spi_tx_npacket;\r
341         pdc_packet_t g_pdc_spi_rx_npacket;\r
342 \r
343         /* Prepare control word and byte count. */\r
344         cmdBuf.uc[0] = FIFO_WRITE;\r
345         cmdBuf.uc[1] = frameID++ & 0x3f;\r
346         cmdBuf.uc[2] = 0;\r
347         cmdBuf.uc[3] = ulActualLength & 0xff;\r
348         cmdBuf.uc[4] = ulActualLength >> 8;\r
349 \r
350         spi_clear_ovres();\r
351 \r
352         /* Prepare PDC transfer. */\r
353         g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;\r
354         g_pdc_spi_tx_packet.ul_size = 5;\r
355 \r
356         g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc;\r
357         g_pdc_spi_rx_packet.ul_size = 5;\r
358 \r
359         g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf;\r
360         g_pdc_spi_tx_npacket.ul_size = ulFIFOLength;\r
361 \r
362         g_pdc_spi_rx_npacket.ul_addr = (uint32_t) tmpbuf;\r
363         g_pdc_spi_rx_npacket.ul_size = ulFIFOLength;\r
364 \r
365         pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
366         pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket);\r
367         #if( TX_USES_RECV == 1 )\r
368                 pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket);\r
369                 spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_ENDRX | SPI_IER_OVRES);\r
370                 pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);\r
371         #else\r
372                 spi_enable_interrupt(KSZ8851SNL_SPI, SPI_SR_TXBUFE | SPI_IER_OVRES);\r
373                 pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_TXTEN);\r
374         #endif\r
375 }\r
376 \r
377 /**\r
378  * \brief Write dummy data to the internal fifo buffer.\r
379  *\r
380  * \param len the amount of dummy data to write.\r
381  */\r
382 void ksz8851_fifo_dummy(uint32_t len)\r
383 {\r
384         pdc_packet_t g_pdc_spi_tx_packet;\r
385         pdc_packet_t g_pdc_spi_rx_packet;\r
386 \r
387         /* Prepare PDC transfer. */\r
388         g_pdc_spi_tx_packet.ul_addr = (uint32_t) tmpbuf;\r
389         g_pdc_spi_tx_packet.ul_size = len;\r
390         g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf;\r
391         g_pdc_spi_rx_packet.ul_size = len;\r
392         pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
393         pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL);\r
394         pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL);\r
395         pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);\r
396 \r
397         while (!(spi_read_status(KSZ8851SNL_SPI) & SPI_SR_ENDRX))\r
398                 ;\r
399 }\r
400 \r
401 void ksz8851snl_set_registers(void)\r
402 {\r
403         /* Init step2-4: write QMU MAC address (low, middle then high). */\r
404         ksz8851_reg_write(REG_MAC_ADDR_0, (ETHERNET_CONF_ETHADDR4 << 8) | ETHERNET_CONF_ETHADDR5);\r
405         ksz8851_reg_write(REG_MAC_ADDR_2, (ETHERNET_CONF_ETHADDR2 << 8) | ETHERNET_CONF_ETHADDR3);\r
406         ksz8851_reg_write(REG_MAC_ADDR_4, (ETHERNET_CONF_ETHADDR0 << 8) | ETHERNET_CONF_ETHADDR1);\r
407 \r
408         /* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */\r
409         ksz8851_reg_write(REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC);\r
410 \r
411         /* Init step6: configure QMU transmit control register. */\r
412         ksz8851_reg_write(REG_TX_CTRL,\r
413                         TX_CTRL_ICMP_CHECKSUM |\r
414                         TX_CTRL_UDP_CHECKSUM |\r
415                         TX_CTRL_TCP_CHECKSUM |\r
416                         TX_CTRL_IP_CHECKSUM |\r
417                         TX_CTRL_FLOW_ENABLE |\r
418                         TX_CTRL_PAD_ENABLE |\r
419                         TX_CTRL_CRC_ENABLE\r
420                 );\r
421 \r
422         /* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */\r
423         ksz8851_reg_write(REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC);\r
424 \r
425         /* Init step8: configure QMU Receive Frame Threshold for one frame. */\r
426         ksz8851_reg_write(REG_RX_FRAME_CNT_THRES, 1);\r
427 \r
428         /* Init step9: configure QMU receive control register1. */\r
429         ksz8851_reg_write(REG_RX_CTRL1,\r
430                         RX_CTRL_UDP_CHECKSUM |\r
431                         RX_CTRL_TCP_CHECKSUM |\r
432                         RX_CTRL_IP_CHECKSUM |\r
433                         RX_CTRL_MAC_FILTER |\r
434                         RX_CTRL_FLOW_ENABLE |\r
435                         RX_CTRL_BROADCAST |\r
436                         RX_CTRL_ALL_MULTICAST|\r
437                         RX_CTRL_UNICAST);\r
438 //      ksz8851_reg_write(REG_RX_CTRL1,\r
439 //                      RX_CTRL_UDP_CHECKSUM |\r
440 //                      RX_CTRL_TCP_CHECKSUM |\r
441 //                      RX_CTRL_IP_CHECKSUM |\r
442 //                      RX_CTRL_FLOW_ENABLE |\r
443 //                      RX_CTRL_PROMISCUOUS);\r
444 \r
445         ksz8851_reg_write(REG_RX_CTRL2,\r
446                         RX_CTRL_IPV6_UDP_NOCHECKSUM |\r
447                         RX_CTRL_UDP_LITE_CHECKSUM |\r
448                         RX_CTRL_ICMP_CHECKSUM |\r
449                         RX_CTRL_BURST_LEN_FRAME);\r
450 \r
451 \r
452 //#define   RXQ_TWOBYTE_OFFSET          (0x0200)    /* Enable adding 2-byte before frame header for IP aligned with DWORD */\r
453 #warning Remember to try the above option to get a 2-byte offset\r
454 \r
455         /* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */\r
456         ksz8851_reg_write( REG_RXQ_CMD, RXQ_CMD_CNTL | RXQ_TWOBYTE_OFFSET );\r
457 \r
458         /* Init step12: adjust SPI data output delay. */\r
459         ksz8851_reg_write(REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1);\r
460 \r
461         /* Init step13: restart auto-negotiation. */\r
462         ksz8851_reg_setbits(REG_PORT_CTRL, PORT_AUTO_NEG_RESTART);\r
463 \r
464         /* Init step13.1: force link in half duplex if auto-negotiation failed. */\r
465         if ((ksz8851_reg_read(REG_PORT_CTRL) & PORT_AUTO_NEG_RESTART) != PORT_AUTO_NEG_RESTART)\r
466         {\r
467                 ksz8851_reg_clrbits(REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX);\r
468         }\r
469 \r
470         /* Init step14: clear interrupt status. */\r
471         ksz8851_reg_write(REG_INT_STATUS, 0xFFFF);\r
472 \r
473         /* Init step15: set interrupt mask. */\r
474         ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
475 \r
476         /* Init step16: enable QMU Transmit. */\r
477         ksz8851_reg_setbits(REG_TX_CTRL, TX_CTRL_ENABLE);\r
478 \r
479         /* Init step17: enable QMU Receive. */\r
480         ksz8851_reg_setbits(REG_RX_CTRL1, RX_CTRL_ENABLE);\r
481 }\r
482 /**\r
483  * \brief KSZ8851SNL initialization function.\r
484  *\r
485  * \return 0 on success, 1 on communication error.\r
486  */\r
487 uint32_t ksz8851snl_init(void)\r
488 {\r
489 uint32_t count = 10;\r
490 uint16_t dev_id = 0;\r
491 uint8_t id_ok = 0;\r
492 \r
493         /* Configure the SPI peripheral. */\r
494         spi_enable_clock(KSZ8851SNL_SPI);\r
495         spi_disable(KSZ8851SNL_SPI);\r
496         spi_reset(KSZ8851SNL_SPI);\r
497         spi_set_master_mode(KSZ8851SNL_SPI);\r
498         spi_disable_mode_fault_detect(KSZ8851SNL_SPI);\r
499         spi_set_peripheral_chip_select_value(KSZ8851SNL_SPI, ~(uint32_t)(1UL << KSZ8851SNL_CS_PIN));\r
500 spi_set_fixed_peripheral_select(KSZ8851SNL_SPI);\r
501 //spi_disable_peripheral_select_decode(KSZ8851SNL_SPI);\r
502 \r
503         spi_set_clock_polarity(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_POLARITY);\r
504         spi_set_clock_phase(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_PHASE);\r
505         spi_set_bits_per_transfer(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN,\r
506                         SPI_CSR_BITS_8_BIT);\r
507         spi_set_baudrate_div(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, (sysclk_get_cpu_hz() / KSZ8851SNL_CLOCK_SPEED));\r
508 //      spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, CONFIG_SPI_MASTER_DELAY_BS,\r
509 //                      CONFIG_SPI_MASTER_DELAY_BCT);\r
510 \r
511 \r
512         spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, 0, 0);\r
513 \r
514         spi_enable(KSZ8851SNL_SPI);\r
515 \r
516         /* Get pointer to UART PDC register base. */\r
517         g_p_spi_pdc = spi_get_pdc_base(KSZ8851SNL_SPI);\r
518         pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);\r
519 \r
520         /* Control RSTN and CSN pin from the driver. */\r
521         gpio_configure_pin(KSZ8851SNL_CSN_GPIO, KSZ8851SNL_CSN_FLAGS);\r
522         gpio_set_pin_high(KSZ8851SNL_CSN_GPIO);\r
523         gpio_configure_pin(KSZ8851SNL_RSTN_GPIO, KSZ8851SNL_RSTN_FLAGS);\r
524 \r
525         /* Reset the Micrel in a proper state. */\r
526         while( count-- )\r
527         {\r
528                 /* Perform hardware reset with respect to the reset timing from the datasheet. */\r
529                 gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO);\r
530                 vTaskDelay(2);\r
531                 gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO);\r
532                 vTaskDelay(2);\r
533 \r
534                 /* Init step1: read chip ID. */\r
535                 dev_id = ksz8851_reg_read(REG_CHIP_ID);\r
536                 if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 )\r
537                 {\r
538                         id_ok = 1;\r
539                         break;\r
540                 }\r
541         }\r
542         if( id_ok != 0 )\r
543         {\r
544                 ksz8851snl_set_registers();\r
545         }\r
546 \r
547         return id_ok ? 1 : -1;\r
548 }\r
549 \r
550 uint32_t ksz8851snl_reinit(void)\r
551 {\r
552 uint32_t count = 10;\r
553 uint16_t dev_id = 0;\r
554 uint8_t id_ok = 0;\r
555         /* Reset the Micrel in a proper state. */\r
556         while( count-- )\r
557         {\r
558                 /* Perform hardware reset with respect to the reset timing from the datasheet. */\r
559                 gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO);\r
560                 vTaskDelay(2);\r
561                 gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO);\r
562                 vTaskDelay(2);\r
563 \r
564                 /* Init step1: read chip ID. */\r
565                 dev_id = ksz8851_reg_read(REG_CHIP_ID);\r
566                 if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 )\r
567                 {\r
568                         id_ok = 1;\r
569                         break;\r
570                 }\r
571         }\r
572         if( id_ok != 0 )\r
573         {\r
574                 ksz8851snl_set_registers();\r
575         }\r
576 \r
577         return id_ok ? 1 : -1;\r
578 }\r
579 \r
580 uint32_t ksz8851snl_reset_rx( void )\r
581 {\r
582 uint16_t usValue;\r
583 \r
584         usValue = ksz8851_reg_read(REG_RX_CTRL1);\r
585 \r
586         usValue &= ~( ( uint16_t ) RX_CTRL_ENABLE | RX_CTRL_FLUSH_QUEUE );\r
587 \r
588         ksz8851_reg_write( REG_RX_CTRL1, usValue ); vTaskDelay( 2 );\r
589         ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_FLUSH_QUEUE ); vTaskDelay( 1 );\r
590         ksz8851_reg_write( REG_RX_CTRL1, usValue ); vTaskDelay( 1 );\r
591         ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_ENABLE ); vTaskDelay( 1 );\r
592 \r
593         return ( uint32_t )usValue;\r
594 }\r
595 \r
596 uint32_t ksz8851snl_reset_tx( void )\r
597 {\r
598 uint16_t usValue;\r
599 \r
600         usValue = ksz8851_reg_read( REG_TX_CTRL );\r
601 \r
602         usValue &= ~( ( uint16_t ) TX_CTRL_ENABLE | TX_CTRL_FLUSH_QUEUE );\r
603 \r
604         ksz8851_reg_write( REG_TX_CTRL, usValue ); vTaskDelay( 2 );\r
605         ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_FLUSH_QUEUE ); vTaskDelay( 1 );\r
606         ksz8851_reg_write( REG_TX_CTRL, usValue ); vTaskDelay( 1 );\r
607         ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_ENABLE ); vTaskDelay( 1 );\r
608 \r
609         return ( uint32_t )usValue;\r
610 }\r