1 /******************************************************************************
2 * Copyright (C) 2010 - 2020 Xilinx, Inc.  All rights reserved.
3 * SPDX-License-Identifier: MIT
4 ******************************************************************************/
5 
6 /*****************************************************************************/
7 /**
8 *
9 * @file xemacps.c
10 * @addtogroup emacps_v3_11
11 * @{
12 *
13 * The XEmacPs driver. Functions in this file are the minimum required functions
14 * for this driver. See xemacps.h for a detailed description of the driver.
15 *
16 * <pre>
17 * MODIFICATION HISTORY:
18 *
19 * Ver   Who  Date     Changes
20 * ----- ---- -------- -------------------------------------------------------
21 * 1.00a wsy  01/10/10 First release
22 * 2.1  srt  07/15/14 Add support for Zynq Ultrascale Mp GEM specification and
23 *              64-bit changes.
24 * 3.00 kvn  02/13/15 Modified code for MISRA-C:2012 compliance.
25 * 3.0  hk   02/20/15 Added support for jumbo frames. Increase AHB burst.
26 *                    Disable extended mode. Perform all 64 bit changes under
27 *                    check for arch64.
28 * 3.1  hk   08/10/15 Update upper 32 bit tx and rx queue ptr registers
29 * 3.5  hk   08/14/17 Update cache coherency information of the interface in
30 *                    its config structure.
31 * 3.8  hk   09/17/18 Cleanup stale comments.
32 * 3.8  mus  11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
33 * 3.10 hk   05/16/19 Clear status registers properly in reset
34 * 3.11 sd   02/14/20 Add clock support
35 *
36 * </pre>
37 ******************************************************************************/
38 
39 /***************************** Include Files *********************************/
40 
41 #include "xemacps.h"
42 
43 /************************** Constant Definitions *****************************/
44 
45 
46 /**************************** Type Definitions *******************************/
47 
48 
49 /***************** Macros (Inline Functions) Definitions *********************/
50 
51 
52 /************************** Function Prototypes ******************************/
53 
54 void XEmacPs_StubHandler(void);    /* Default handler routine */
55 
56 /************************** Variable Definitions *****************************/
57 
58 
59 /*****************************************************************************/
60 /**
61 * Initialize a specific XEmacPs instance/driver. The initialization entails:
62 * - Initialize fields of the XEmacPs instance structure
63 * - Reset hardware and apply default options
64 * - Configure the DMA channels
65 *
66 * The PHY is setup independently from the device. Use the MII or whatever other
67 * interface may be present for setup.
68 *
69 * @param InstancePtr is a pointer to the instance to be worked on.
70 * @param CfgPtr is the device configuration structure containing required
71 *        hardware build data.
72 * @param EffectiveAddress is the base address of the device. If address
73 *        translation is not utilized, this parameter can be passed in using
74 *        CfgPtr->Config.BaseAddress to specify the physical base address.
75 *
76 * @return
77 * - XST_SUCCESS if initialization was successful
78 *
79 ******************************************************************************/
XEmacPs_CfgInitialize(XEmacPs * InstancePtr,XEmacPs_Config * CfgPtr,UINTPTR EffectiveAddress)80 LONG XEmacPs_CfgInitialize(XEmacPs *InstancePtr, XEmacPs_Config * CfgPtr,
81                UINTPTR EffectiveAddress)
82 {
83     /* Verify arguments */
84     Xil_AssertNonvoid(InstancePtr != NULL);
85     Xil_AssertNonvoid(CfgPtr != NULL);
86 
87     /* Set device base address and ID */
88     InstancePtr->Config.DeviceId = CfgPtr->DeviceId;
89     InstancePtr->Config.BaseAddress = EffectiveAddress;
90     InstancePtr->Config.IsCacheCoherent = CfgPtr->IsCacheCoherent;
91 #if defined  (XCLOCKING)
92     InstancePtr->Config.RefClk = CfgPtr->RefClk;
93 #endif
94 
95     /* Set callbacks to an initial stub routine */
96     InstancePtr->SendHandler = ((XEmacPs_Handler)((void*)XEmacPs_StubHandler));
97     InstancePtr->RecvHandler = ((XEmacPs_Handler)(void*)XEmacPs_StubHandler);
98     InstancePtr->ErrorHandler = ((XEmacPs_ErrHandler)(void*)XEmacPs_StubHandler);
99 
100     /* Reset the hardware and set default options */
101     InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
102     XEmacPs_Reset(InstancePtr);
103 
104     return (LONG)(XST_SUCCESS);
105 }
106 
107 
108 /*****************************************************************************/
109 /**
110 * Start the Ethernet controller as follows:
111 *   - Enable transmitter if XTE_TRANSMIT_ENABLE_OPTION is set
112 *   - Enable receiver if XTE_RECEIVER_ENABLE_OPTION is set
113 *   - Start the SG DMA send and receive channels and enable the device
114 *     interrupt
115 *
116 * @param InstancePtr is a pointer to the instance to be worked on.
117 *
118 * @return N/A
119 *
120 * @note
121 * Hardware is configured with scatter-gather DMA, the driver expects to start
122 * the scatter-gather channels and expects that the user has previously set up
123 * the buffer descriptor lists.
124 *
125 * This function makes use of internal resources that are shared between the
126 * Start, Stop, and Set/ClearOptions functions. So if one task might be setting
127 * device options while another is trying to start the device, the user is
128 * required to provide protection of this shared data (typically using a
129 * semaphore).
130 *
131 * This function must not be preempted by an interrupt that may service the
132 * device.
133 *
134 ******************************************************************************/
XEmacPs_Start(XEmacPs * InstancePtr)135 void XEmacPs_Start(XEmacPs *InstancePtr)
136 {
137     u32 Reg;
138 
139     /* Assert bad arguments and conditions */
140     Xil_AssertVoid(InstancePtr != NULL);
141     Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
142 
143 #if defined  (XCLOCKING)
144     if (InstancePtr->IsStarted != (u32)XIL_COMPONENT_IS_STARTED) {
145         Xil_ClockEnable(InstancePtr->Config.RefClk);
146     }
147 #endif
148 
149     /* Start DMA */
150     /* When starting the DMA channels, both transmit and receive sides
151      * need an initialized BD list.
152      */
153     if (InstancePtr->Version == 2) {
154         Xil_AssertVoid(InstancePtr->RxBdRing.BaseBdAddr != 0);
155         Xil_AssertVoid(InstancePtr->TxBdRing.BaseBdAddr != 0);
156     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
157                XEMACPS_RXQBASE_OFFSET,
158                InstancePtr->RxBdRing.BaseBdAddr);
159 
160     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
161                XEMACPS_TXQBASE_OFFSET,
162                InstancePtr->TxBdRing.BaseBdAddr);
163     }
164 
165     /* clear any existed int status */
166     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET,
167                XEMACPS_IXR_ALL_MASK);
168 
169     /* Enable transmitter if not already enabled */
170     if ((InstancePtr->Options & (u32)XEMACPS_TRANSMITTER_ENABLE_OPTION)!=0x00000000U) {
171         Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
172                     XEMACPS_NWCTRL_OFFSET);
173         if ((!(Reg & XEMACPS_NWCTRL_TXEN_MASK))==TRUE) {
174             XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
175                        XEMACPS_NWCTRL_OFFSET,
176                    Reg | (u32)XEMACPS_NWCTRL_TXEN_MASK);
177         }
178     }
179 
180     /* Enable receiver if not already enabled */
181     if ((InstancePtr->Options & XEMACPS_RECEIVER_ENABLE_OPTION) != 0x00000000U) {
182         Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
183                     XEMACPS_NWCTRL_OFFSET);
184         if ((!(Reg & XEMACPS_NWCTRL_RXEN_MASK))==TRUE) {
185             XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
186                        XEMACPS_NWCTRL_OFFSET,
187                    Reg | (u32)XEMACPS_NWCTRL_RXEN_MASK);
188         }
189     }
190 
191         /* Enable TX and RX interrupts */
192         XEmacPs_IntEnable(InstancePtr, (XEMACPS_IXR_TX_ERR_MASK |
193     XEMACPS_IXR_RX_ERR_MASK | (u32)XEMACPS_IXR_FRAMERX_MASK |
194     (u32)XEMACPS_IXR_TXCOMPL_MASK));
195 
196     /* Enable TX Q1 Interrupts */
197     if (InstancePtr->Version > 2)
198         XEmacPs_IntQ1Enable(InstancePtr, XEMACPS_INTQ1_IXR_ALL_MASK);
199 
200     /* Mark as started */
201     InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED;
202 
203     return;
204 }
205 
206 
207 /*****************************************************************************/
208 /**
209 * Gracefully stop the Ethernet MAC as follows:
210 *   - Disable all interrupts from this device
211 *   - Stop DMA channels
212 *   - Disable the tansmitter and receiver
213 *
214 * Device options currently in effect are not changed.
215 *
216 * This function will disable all interrupts. Default interrupts settings that
217 * had been enabled will be restored when XEmacPs_Start() is called.
218 *
219 * @param InstancePtr is a pointer to the instance to be worked on.
220 *
221 * @note
222 * This function makes use of internal resources that are shared between the
223 * Start, Stop, SetOptions, and ClearOptions functions. So if one task might be
224 * setting device options while another is trying to start the device, the user
225 * is required to provide protection of this shared data (typically using a
226 * semaphore).
227 *
228 * Stopping the DMA channels causes this function to block until the DMA
229 * operation is complete.
230 *
231 ******************************************************************************/
XEmacPs_Stop(XEmacPs * InstancePtr)232 void XEmacPs_Stop(XEmacPs *InstancePtr)
233 {
234     u32 Reg;
235 
236     Xil_AssertVoid(InstancePtr != NULL);
237     Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
238 
239     /* Disable all interrupts */
240     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_IDR_OFFSET,
241                XEMACPS_IXR_ALL_MASK);
242 
243     /* Disable the receiver & transmitter */
244     Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
245                 XEMACPS_NWCTRL_OFFSET);
246     Reg &= (u32)(~XEMACPS_NWCTRL_RXEN_MASK);
247     Reg &= (u32)(~XEMACPS_NWCTRL_TXEN_MASK);
248     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
249                XEMACPS_NWCTRL_OFFSET, Reg);
250 
251     /* Mark as stopped */
252     InstancePtr->IsStarted = 0U;
253 #if defined  (XCLOCKING)
254     Xil_ClockDisable(InstancePtr->Config.RefClk);
255 #endif
256 }
257 
258 
259 /*****************************************************************************/
260 /**
261 * Perform a graceful reset of the Ethernet MAC. Resets the DMA channels, the
262 * transmitter, and the receiver.
263 *
264 * Steps to reset
265 * - Stops transmit and receive channels
266 * - Stops DMA
267 * - Configure transmit and receive buffer size to default
268 * - Clear transmit and receive status register and counters
269 * - Clear all interrupt sources
270 * - Clear phy (if there is any previously detected) address
271 * - Clear MAC addresses (1-4) as well as Type IDs and hash value
272 *
273 * All options are placed in their default state. Any frames in the
274 * descriptor lists will remain in the lists. The side effect of doing
275 * this is that after a reset and following a restart of the device, frames
276 * were in the list before the reset may be transmitted or received.
277 *
278 * The upper layer software is responsible for re-configuring (if necessary)
279 * and restarting the MAC after the reset. Note also that driver statistics
280 * are not cleared on reset. It is up to the upper layer software to clear the
281 * statistics if needed.
282 *
283 * When a reset is required, the driver notifies the upper layer software of
284 * this need through the ErrorHandler callback and specific status codes.
285 * The upper layer software is responsible for calling this Reset function
286 * and then re-configuring the device.
287 *
288 * @param InstancePtr is a pointer to the instance to be worked on.
289 *
290 ******************************************************************************/
XEmacPs_Reset(XEmacPs * InstancePtr)291 void XEmacPs_Reset(XEmacPs *InstancePtr)
292 {
293     u32 Reg;
294     u8 i;
295     s8 EmacPs_zero_MAC[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
296 
297     Xil_AssertVoid(InstancePtr != NULL);
298     Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
299 
300     /* Stop the device and reset hardware */
301     XEmacPs_Stop(InstancePtr);
302     InstancePtr->Options = XEMACPS_DEFAULT_OPTIONS;
303 
304     InstancePtr->Version = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, 0xFC);
305 
306     InstancePtr->Version = (InstancePtr->Version >> 16) & 0xFFF;
307 
308     InstancePtr->MaxMtuSize = XEMACPS_MTU;
309     InstancePtr->MaxFrameSize = XEMACPS_MTU + XEMACPS_HDR_SIZE +
310                     XEMACPS_TRL_SIZE;
311     InstancePtr->MaxVlanFrameSize = InstancePtr->MaxFrameSize +
312                     XEMACPS_HDR_VLAN_SIZE;
313     InstancePtr->RxBufMask = XEMACPS_RXBUF_LEN_MASK;
314 
315     /* Setup hardware with default values */
316     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
317             XEMACPS_NWCTRL_OFFSET,
318             (XEMACPS_NWCTRL_STATCLR_MASK |
319             XEMACPS_NWCTRL_MDEN_MASK) &
320             (u32)(~XEMACPS_NWCTRL_LOOPEN_MASK));
321 
322     Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
323             XEMACPS_NWCFG_OFFSET);
324     Reg &= XEMACPS_NWCFG_MDCCLKDIV_MASK;
325 
326     Reg = Reg | (u32)XEMACPS_NWCFG_100_MASK |
327             (u32)XEMACPS_NWCFG_FDEN_MASK |
328             (u32)XEMACPS_NWCFG_UCASTHASHEN_MASK;
329 
330     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
331                     XEMACPS_NWCFG_OFFSET, Reg);
332     if (InstancePtr->Version > 2) {
333         XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET,
334             (XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET) |
335                 XEMACPS_NWCFG_DWIDTH_64_MASK));
336     }
337 
338     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
339             XEMACPS_DMACR_OFFSET,
340             (((((u32)XEMACPS_RX_BUF_SIZE / (u32)XEMACPS_RX_BUF_UNIT) +
341                 (((((u32)XEMACPS_RX_BUF_SIZE %
342                 (u32)XEMACPS_RX_BUF_UNIT))!=(u32)0) ? 1U : 0U)) <<
343                 (u32)(XEMACPS_DMACR_RXBUF_SHIFT)) &
344                 (u32)(XEMACPS_DMACR_RXBUF_MASK)) |
345                 (u32)XEMACPS_DMACR_RXSIZE_MASK |
346                 (u32)XEMACPS_DMACR_TXSIZE_MASK);
347 
348 
349     if (InstancePtr->Version > 2) {
350         XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
351             (XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET) |
352 #if defined(__aarch64__) || defined(__arch64__)
353             (u32)XEMACPS_DMACR_ADDR_WIDTH_64 |
354 #endif
355             (u32)XEMACPS_DMACR_INCR16_AHB_BURST));
356     }
357 
358     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
359                XEMACPS_TXSR_OFFSET, XEMACPS_SR_ALL_MASK);
360 
361     XEmacPs_SetQueuePtr(InstancePtr, 0, 0x00U, (u16)XEMACPS_SEND);
362     if (InstancePtr->Version > 2)
363         XEmacPs_SetQueuePtr(InstancePtr, 0, 0x01U, (u16)XEMACPS_SEND);
364     XEmacPs_SetQueuePtr(InstancePtr, 0, 0x00U, (u16)XEMACPS_RECV);
365 
366     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
367                XEMACPS_RXSR_OFFSET, XEMACPS_SR_ALL_MASK);
368 
369     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_IDR_OFFSET,
370                XEMACPS_IXR_ALL_MASK);
371 
372     Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
373                 XEMACPS_ISR_OFFSET);
374     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET,
375                Reg);
376 
377     XEmacPs_ClearHash(InstancePtr);
378 
379     for (i = 1U; i < 5U; i++) {
380         (void)XEmacPs_SetMacAddress(InstancePtr, EmacPs_zero_MAC, i);
381         (void)XEmacPs_SetTypeIdCheck(InstancePtr, 0x00000000U, i);
382     }
383 
384     /* clear all counters */
385     for (i = 0U; i < (u8)((XEMACPS_LAST_OFFSET - XEMACPS_OCTTXL_OFFSET) / 4U);
386          i++) {
387         (void)XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
388                                    XEMACPS_OCTTXL_OFFSET + (u32)(((u32)i) * ((u32)4)));
389     }
390 
391     /* Disable the receiver */
392     Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
393                 XEMACPS_NWCTRL_OFFSET);
394     Reg &= (u32)(~XEMACPS_NWCTRL_RXEN_MASK);
395     XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
396                XEMACPS_NWCTRL_OFFSET, Reg);
397 
398     /* Sync default options with hardware but leave receiver and
399          * transmitter disabled. They get enabled with XEmacPs_Start() if
400      * XEMACPS_TRANSMITTER_ENABLE_OPTION and
401          * XEMACPS_RECEIVER_ENABLE_OPTION are set.
402      */
403     (void)XEmacPs_SetOptions(InstancePtr, InstancePtr->Options &
404                 ~((u32)XEMACPS_TRANSMITTER_ENABLE_OPTION |
405                   (u32)XEMACPS_RECEIVER_ENABLE_OPTION));
406 
407     (void)XEmacPs_ClearOptions(InstancePtr, ~InstancePtr->Options);
408 }
409 
410 
411 /******************************************************************************/
412 /**
413  * This is a stub for the asynchronous callbacks. The stub is here in case the
414  * upper layer forgot to set the handler(s). On initialization, all handlers are
415  * set to this callback. It is considered an error for this handler to be
416  * invoked.
417  *
418  ******************************************************************************/
XEmacPs_StubHandler(void)419 void XEmacPs_StubHandler(void)
420 {
421     Xil_AssertVoidAlways();
422 }
423 
424 /*****************************************************************************/
425 /**
426 * This function sets the start address of the transmit/receive buffer queue.
427 *
428 * @param    InstancePtr is a pointer to the instance to be worked on.
429 * @param    QPtr is the address of the Queue to be written
430 * @param    QueueNum is the Buffer Queue Index
431 * @param    Direction indicates Transmit/Receive
432 *
433 * @note
434 * The buffer queue addresses has to be set before starting the transfer, so
435 * this function has to be called in prior to XEmacPs_Start()
436 *
437 ******************************************************************************/
XEmacPs_SetQueuePtr(XEmacPs * InstancePtr,UINTPTR QPtr,u8 QueueNum,u16 Direction)438 void XEmacPs_SetQueuePtr(XEmacPs *InstancePtr, UINTPTR QPtr, u8 QueueNum,
439              u16 Direction)
440 {
441     /* Assert bad arguments and conditions */
442     Xil_AssertVoid(InstancePtr != NULL);
443     Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
444 
445         /* If already started, then there is nothing to do */
446         if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
447                 return;
448         }
449 
450     if (QueueNum == 0x00U) {
451         if (Direction == XEMACPS_SEND) {
452             XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
453                 XEMACPS_TXQBASE_OFFSET,
454                 (QPtr & ULONG64_LO_MASK));
455         } else {
456             XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
457                 XEMACPS_RXQBASE_OFFSET,
458                 (QPtr & ULONG64_LO_MASK));
459         }
460     }
461      else {
462         XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
463             XEMACPS_TXQ1BASE_OFFSET,
464             (QPtr & ULONG64_LO_MASK));
465     }
466 #ifdef __aarch64__
467     if (Direction == XEMACPS_SEND) {
468         /* Set the MSB of TX Queue start address */
469         XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
470                 XEMACPS_MSBBUF_TXQBASE_OFFSET,
471                 (u32)((QPtr & ULONG64_HI_MASK) >> 32U));
472     } else {
473         /* Set the MSB of RX Queue start address */
474         XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
475                 XEMACPS_MSBBUF_RXQBASE_OFFSET,
476                 (u32)((QPtr & ULONG64_HI_MASK) >> 32U));
477     }
478 #endif
479 }
480 /** @} */
481