1 /*
2  * Copyright (C) 2010 - 2019 Xilinx, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  *
29  */
30 
31 #include "netif/xemacpsif.h"
32 #include "lwipopts.h"
33 
34 #if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
35     XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
36 #define PCM_PMA_CORE_PRESENT
37 #else
38 #undef PCM_PMA_CORE_PRESENT
39 #endif
40 
41 u32_t link_speed = 100;
42 extern XEmacPs_Config XEmacPs_ConfigTable[];
43 extern u32_t phymapemac0[32];
44 extern u32_t phymapemac1[32];
45 extern u32_t phyaddrforemac;
46 extern enum ethernet_link_status eth_link_status;
47 
48 #ifdef OS_IS_FREERTOS
49 extern long xInsideISR;
50 #endif
51 
xemacps_lookup_config(unsigned mac_base)52 XEmacPs_Config *xemacps_lookup_config(unsigned mac_base)
53 {
54     XEmacPs_Config *cfgptr = NULL;
55     s32_t i;
56 
57     for (i = 0; i < XPAR_XEMACPS_NUM_INSTANCES; i++) {
58         if (XEmacPs_ConfigTable[i].BaseAddress == mac_base) {
59             cfgptr = &XEmacPs_ConfigTable[i];
60             break;
61         }
62     }
63 
64     return (cfgptr);
65 }
66 
init_emacps(xemacpsif_s * xemacps,struct netif * netif)67 void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
68 {
69     XEmacPs *xemacpsp;
70     s32_t status = XST_SUCCESS;
71     u32_t i;
72     u32_t phyfoundforemac0 = FALSE;
73     u32_t phyfoundforemac1 = FALSE;
74 
75     xemacpsp = &xemacps->emacps;
76 
77 #ifdef ZYNQMP_USE_JUMBO
78     XEmacPs_SetOptions(xemacpsp, XEMACPS_JUMBO_ENABLE_OPTION);
79 #endif
80 
81 #ifdef LWIP_IGMP
82     XEmacPs_SetOptions(xemacpsp, XEMACPS_MULTICAST_OPTION);
83 #endif
84 
85     /* set mac address */
86     status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
87     if (status != XST_SUCCESS) {
88         xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
89     }
90 
91     XEmacPs_SetMdioDivisor(xemacpsp, MDC_DIV_224);
92 
93 /*  Please refer to file header comments for the file xemacpsif_physpeed.c
94  *  to know more about the PHY programming sequence.
95  *  For PCS PMA core, phy_setup_emacps is called with the predefined PHY address
96  *  exposed through xaparemeters.h
97  *  For RGMII case, assuming multiple PHYs can be present on the MDIO bus,
98  *  detect_phy is called to get the addresses of the PHY present on
99  *  a particular MDIO bus (emac0 or emac1). This address map is populated
100  *  in phymapemac0 or phymapemac1.
101  *  phy_setup_emacps is then called for each PHY present on the MDIO bus.
102  */
103 #ifdef PCM_PMA_CORE_PRESENT
104 #ifdef  XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
105     link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_1000BASEX_PHYADDR);
106 #elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
107     link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_SGMII_PHYADDR);
108 #endif
109 #else
110     detect_phy(xemacpsp);
111     for (i = 31; i > 0; i--) {
112         if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
113             if (phymapemac0[i] == TRUE) {
114                 link_speed = phy_setup_emacps(xemacpsp, i);
115                 phyfoundforemac0 = TRUE;
116                 phyaddrforemac = i;
117             }
118         } else {
119             if (phymapemac1[i] == TRUE) {
120                 link_speed = phy_setup_emacps(xemacpsp, i);
121                 phyfoundforemac1 = TRUE;
122                 phyaddrforemac = i;
123             }
124         }
125     }
126     /* If no PHY was detected, use broadcast PHY address of 0 */
127     if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
128         if (phyfoundforemac0 == FALSE)
129             link_speed = phy_setup_emacps(xemacpsp, 0);
130     } else {
131         if (phyfoundforemac1 == FALSE)
132             link_speed = phy_setup_emacps(xemacpsp, 0);
133     }
134 #endif
135 
136     if (link_speed == XST_FAILURE) {
137         eth_link_status = ETH_LINK_DOWN;
138         xil_printf("Phy setup failure %s \n\r",__func__);
139         return;
140     } else {
141         eth_link_status = ETH_LINK_UP;
142     }
143 
144     XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
145     /* Setting the operating speed of the MAC needs a delay. */
146     {
147         volatile s32_t wait;
148         for (wait=0; wait < 20000; wait++);
149     }
150 }
151 
init_emacps_on_error(xemacpsif_s * xemacps,struct netif * netif)152 void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
153 {
154     XEmacPs *xemacpsp;
155     s32_t status = XST_SUCCESS;
156 
157     xemacpsp = &xemacps->emacps;
158 
159     /* set mac address */
160     status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
161     if (status != XST_SUCCESS) {
162         xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
163     }
164 
165     XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
166 
167     /* Setting the operating speed of the MAC needs a delay. */
168     {
169         volatile s32_t wait;
170         for (wait=0; wait < 20000; wait++);
171     }
172 }
173 
setup_isr(struct xemac_s * xemac)174 void setup_isr (struct xemac_s *xemac)
175 {
176     xemacpsif_s   *xemacpsif;
177 
178     xemacpsif = (xemacpsif_s *)(xemac->state);
179     /*
180      * Setup callbacks
181      */
182     XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
183                      (void *) emacps_send_handler,
184                      (void *) xemac);
185 
186     XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
187                     (void *) emacps_recv_handler,
188                     (void *) xemac);
189 
190     XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
191                     (void *) emacps_error_handler,
192                     (void *) xemac);
193 }
194 
start_emacps(xemacpsif_s * xemacps)195 void start_emacps (xemacpsif_s *xemacps)
196 {
197     /* start the temac */
198     XEmacPs_Start(&xemacps->emacps);
199 }
200 
restart_emacps_transmitter(xemacpsif_s * xemacps)201 void restart_emacps_transmitter (xemacpsif_s *xemacps) {
202     u32_t Reg;
203     Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
204                     XEMACPS_NWCTRL_OFFSET);
205     Reg = Reg & (~XEMACPS_NWCTRL_TXEN_MASK);
206     XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
207                                         XEMACPS_NWCTRL_OFFSET, Reg);
208 
209     Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
210                         XEMACPS_NWCTRL_OFFSET);
211     Reg = Reg | (XEMACPS_NWCTRL_TXEN_MASK);
212     XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
213                                         XEMACPS_NWCTRL_OFFSET, Reg);
214 }
215 
emacps_error_handler(void * arg,u8 Direction,u32 ErrorWord)216 void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord)
217 {
218     struct xemac_s *xemac;
219     xemacpsif_s   *xemacpsif;
220     XEmacPs_BdRing *rxring;
221     XEmacPs_BdRing *txring;
222 #ifdef OS_IS_FREERTOS
223     xInsideISR++;
224 #endif
225 
226     xemac = (struct xemac_s *)(arg);
227     xemacpsif = (xemacpsif_s *)(xemac->state);
228     rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
229     txring = &XEmacPs_GetTxRing(&xemacpsif->emacps);
230 
231     if (ErrorWord != 0) {
232         switch (Direction) {
233             case XEMACPS_RECV:
234             if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
235                 LWIP_DEBUGF(NETIF_DEBUG, ("Receive DMA error\r\n"));
236                 HandleEmacPsError(xemac);
237             }
238             if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
239                 LWIP_DEBUGF(NETIF_DEBUG, ("Receive over run\r\n"));
240                 emacps_recv_handler(arg);
241                 setup_rx_bds(xemacpsif, rxring);
242             }
243             if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
244                 LWIP_DEBUGF(NETIF_DEBUG, ("Receive buffer not available\r\n"));
245                 emacps_recv_handler(arg);
246                 setup_rx_bds(xemacpsif, rxring);
247             }
248             break;
249             case XEMACPS_SEND:
250             if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
251                 LWIP_DEBUGF(NETIF_DEBUG, ("Transmit DMA error\r\n"));
252                 HandleEmacPsError(xemac);
253             }
254             if (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
255                 LWIP_DEBUGF(NETIF_DEBUG, ("Transmit under run\r\n"));
256                 HandleTxErrors(xemac);
257             }
258             if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
259                 LWIP_DEBUGF(NETIF_DEBUG, ("Transmit buffer exhausted\r\n"));
260                 HandleTxErrors(xemac);
261             }
262             if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
263                 LWIP_DEBUGF(NETIF_DEBUG, ("Transmit retry excessed limits\r\n"));
264                 HandleTxErrors(xemac);
265             }
266             if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
267                 LWIP_DEBUGF(NETIF_DEBUG, ("Transmit collision\r\n"));
268                 // process_sent_bds(xemacpsif, txring);
269             }
270             break;
271         }
272     }
273 #ifdef OS_IS_FREERTOS
274     xInsideISR--;
275 #endif
276 }
277