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