1 /*-----------------------------------------------------------------------------
2 * EcDeviceCPSW.cpp
3 * Copyright acontis technologies GmbH, Weingarten, Germany
4 * Response Kai Olbrich
5 * Description CPSW EtherCAT linklayer driver.
6 *---------------------------------------------------------------------------*/
8 /*-INCLUDES------------------------------------------------------------------*/
10 #include <LinkOsLayer.h>
11 #include <EcLink.h>
12 #include <EthernetServices.h>
14 #include "CPSWPrivate.h"
15 #include "EcDeviceCPSW.h"
17 /*-DEFINES-------------------------------------------------------------------*/
19 #define CPSWID "CPSW"
20 #define MDIO_ERROR 0xFFFFFFFF
22 #ifdef __cplusplus
23 # define CCALLING extern "C"
24 #else
25 # define CCALLING
26 #endif /* ifdef __cplusplus */
28 #ifdef USE_CPPI_RAM
29 # if (CPSW_RXDESCNT * 16 + CPSW_TXDESCNT * 16) > (CPSW_SOCDMA_LENGTH / CPSW_SLAVECNT)
30 # error To many DMA descriptors or undef USE_CPPI_RAM
31 # endif
32 #endif
34 #ifdef LINUX
35 # define CPSW_ENABLE_CLOCKS
36 #endif
38 #undef TRACE
40 #define ALIGN_UP(addr, size) (((addr)+((size)-1)) & (~((size)-1)))
41 #define ALIGN_DOWN(addr, size) ((addr) & (~((size)-1)))
43 #define CPSW_PAGE_SIZE 0x1000
44 #define PAGE_DOWN(addr) ALIGN_DOWN((addr), CPSW_PAGE_SIZE)
45 #define PAGE_UP(addr) ALIGN_UP((addr), CPSW_PAGE_SIZE)
46 #define CPSW_DMA_ALIGN(addr) ALIGN_UP((addr), CPSW_DMA_ALIGNMENT)
47 #define CPSW_CACHE_DOWN(addr) ALIGN_DOWN((addr), CACHELINE_SIZE)
48 #define CPSW_CACHE_UP(addr) ALIGN_UP((addr), CACHELINE_SIZE)
50 #define DMACHAN_LOWPRIO 0
51 #define DMACHAN_HIGHPRIO 7
52 #define PRI2DMACHAN(prio) (((prio) == 0) ? DMACHAN_LOWPRIO : DMACHAN_HIGHPRIO)
53 #define DMACHAN_INVERSE(chan) (((chan) == DMACHAN_HIGHPRIO) ? DMACHAN_LOWPRIO : DMACHAN_HIGHPRIO)
55 // MSVC will do bytewise stores (4 * strb instead of str) if an 32bit register is
56 // written e.g. with (pReg->arry[i] = 0).
57 // Use this macro to atomic write a dword!
58 #define W32(reg, val) \
59 w32(((volatile EC_T_DWORD*) &(reg)), (val))
61 // MSVC will do bytewise load (4 * ldrb instead of ldr) if an 32bit register is
62 // read e.g. with (val = pReg->arry[i]).
63 // Use this macro to atomic read a dword!
64 #define R32(reg) \
65 r32((volatile EC_T_DWORD*) &(reg))
67 #define NEXT_RX_DESC_IDX(idx) (((idx) + 1) & (CPSW_RXDESCNT - 1))
68 #define PREV_RX_DESC_IDX(idx) (((idx) - 1) & (CPSW_RXDESCNT - 1))
69 #define RX_DESC_PTR(idx) (&pAdapter->pRxDesc[(idx)])
71 #define NEXT_TX_DESC_IDX(idx) (((idx) + 1) & (CPSW_TXDESCNT - 1))
72 #define PREV_TX_DESC_IDX(idx) (((idx) - 1) & (CPSW_TXDESCNT - 1))
73 #define TX_DESC_PTR(idx) (&pAdapter->pTxDesc[(idx)])
75 #define NEXT_RX_DMABUF_IDX(idx) (((idx) + 1) & (CPSW_RXDMABUFCNT - 1))
76 #define RX_DMABUF_PTR(idx) ((T_CPSW_FRAMEBUFENTRY *) (pAdapter->pRxBuffer + (idx) * CPSW_RXBUFLEN))
77 #if defined COPY_FRAME
78 #define NEXT_RX_CACHEDBUF_IDX(idx) (((idx) + 1) & (CPSW_RXCACHEDBUFCNT - 1))
79 #define RX_CACHEDBUF_PTR(idx) ((T_CPSW_FRAMEBUFENTRY *) (pAdapter->pRxCachedBuffer + (idx) * CPSW_RXBUFLEN))
80 #endif
82 #define NEXT_TX_DMABUF_IDX(idx) (((idx) + 1) & (CPSW_TXDMABUFCNT - 1))
83 #define TX_DMABUF_PTR(idx) ((T_CPSW_FRAMEBUFENTRY *) (pAdapter->pTxBuffer + (idx) * CPSW_TXBUFLEN))
84 #if defined COPY_FRAME
85 #define NEXT_TX_CACHEDBUF_IDX(idx) (((idx) + 1) & (CPSW_TXCACHEDBUFCNT - 1))
86 #define TX_CACHEDBUF_PTR(idx) ((T_CPSW_FRAMEBUFENTRY *) (pAdapter->pTxCachedBuffer + (idx) * CPSW_TXBUFLEN))
87 #endif
89 #ifndef PRINT
90 # if 0 // Used for tracing
91 # define PRINT(msg, ...) fprintf(stdout, (msg), __VA_ARGS__); fflush(stdout)
92 # elif defined __GNUC__ || (defined __TI_COMPILER_VERSION__ && __TI_COMPILER_VERSION__ > 5002000)
93 # define PRINT(msg, ...) LinkOsDbgMsg((msg), ##__VA_ARGS__)
94 # else
95 # define PRINT(msg, ...) LinkOsDbgMsg((msg), __VA_ARGS__)
96 # endif
97 #endif
99 #ifdef DEBUG
100 # if defined STARTERWARE_NOOS
101 int G_bCPSWverbose;
102 # define DBG if (G_bCPSWverbose) PRINT
103 # elif defined __GNUC__
104 # define DBG(msg, ...) PRINT(CPSWID " DBG: " msg, ##__VA_ARGS__)
105 # else
106 # define DBG(msg, ...) PRINT(CPSWID " DBG: " msg, __VA_ARGS__)
107 # endif
108 #else
109 # define DBG(msg, ...)
110 #endif
112 #ifdef TRACE
113 # if defined __GNUC__
114 # define TRC(msg, ...) PRINT(CPSWID " TRC: " msg, ##__VA_ARGS__)
115 # else
116 # define TRC(msg, ...) PRINT(CPSWID " TRC: " msg, __VA_ARGS__)
117 # endif
118 #else
119 # define TRC(msg, ...)
120 #endif
122 #define _TRC(msg, ...) // Noop. Disabled TRC()
123 #if defined STARTERWARE_NOOS
124 # define INF PRINT
125 # define ERR PRINT
126 #elif defined __GNUC__ || (defined __TI_COMPILER_VERSION__ && __TI_COMPILER_VERSION__ > 5002000)
127 # define INF(msg, ...) PRINT(CPSWID " INF: " msg, ##__VA_ARGS__)
128 # define ERR(msg, ...) PRINT(CPSWID " ERR: " msg, ##__VA_ARGS__)
129 #else
130 # define INF(msg, ...) PRINT(CPSWID " INF: " msg, __VA_ARGS__)
131 # define ERR(msg, ...) PRINT(CPSWID " ERR: " msg, __VA_ARGS__)
132 #endif
134 #if defined STARTERWARE_NOOS && defined ADAPTER_DESC_FROM_UC_MEM
135 CCALLING EC_T_DWORD GetStartAddrDdrUc(void);
136 #endif
138 /***************************************************************************************************
139 * FORWARD DECLARATIONS
140 */
142 static EC_T_DWORD EcLinkClose(void *pvInstance);
143 static EC_T_DWORD EcLinkAllocSendFrameFromDma(PT_CPSW_INTERNAL pAdapter, EC_T_LINK_FRAMEDESC* pLinkFrameDesc, EC_T_DWORD dwSize);
144 static EC_T_LINKSTATUS EcLinkGetStatus(void *pvInstance);
145 static EC_T_DWORD EcLinkIrqOpen(void *pvContext);
146 static EC_T_DWORD EcLinkIrqClose(void *pvContext);
147 static EC_T_DWORD EcLinkIrqAck(void *pvContext);
148 static EC_T_DWORD DoHandleInterrupt(void * pvLinkParms);
150 static EC_T_BOOL ListCanAddAdapter(PT_CPSW_INTERNAL pAdapter);
151 static EC_T_BOOL ListAddOI(PT_CPSW_INTERNAL poAdapter);
152 static EC_T_BOOL ListRmOI(PT_CPSW_INTERNAL poAdapter);
154 static EC_T_DWORD CPSWMapMemory(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD dwBase, EC_T_DWORD *pdwBaseMapped);
155 static void CPSWMapRegisterSet(PT_CPSW_INTERNAL pAdapter);
156 static void CPSWReset(PT_CPSW_INTERNAL pAdapter);
157 static void CPSWTeardown(PT_CPSW_INTERNAL pAdapter);
158 static void CPSWSetupRxDtors(PT_CPSW_INTERNAL pAdapter);
159 static void CPSWSetupTxDtors(PT_CPSW_INTERNAL pAdapter);
160 static void CPSWSetupBuffers(PT_CPSW_INTERNAL pAdapter);
161 static T_CPSW_FRAMEBUFENTRY* CPSWAllocRxBuffer(PT_CPSW_INTERNAL pAdapter);
162 static T_CPSW_FRAMEBUFENTRY* CPSWAllocTxBuffer(PT_CPSW_INTERNAL pAdapter);
163 static void CPSWInitializeHardware(PT_CPSW_INTERNAL pAdapter);
164 static EC_T_DWORD CPSWMdioRead(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD dwRegNo);
165 static EC_T_BOOL CPSWMdioWrite(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD dwRegNo, EC_T_DWORD dwValue);
166 static EC_T_BOOL CPSWPhySetup(PT_CPSW_INTERNAL pAdapter);
167 static EC_T_BOOL CPSWPhyQueryCapabilities(PT_CPSW_INTERNAL pAdapter);
168 static EC_T_DWORD CPSWPhyUpdateLinkStatus(PT_CPSW_INTERNAL pAdapter);
169 static void CPSWUpdateMacSpeed(PT_CPSW_INTERNAL pAdapter);
170 static void CPSWCheckId(PT_CPSW_INTERNAL pAdapter);
171 #ifdef CPSW_ENABLE_CLOCKS
172 static void CPSWClkEnable(PT_CPSW_INTERNAL pAdapter);
173 #endif
174 static void CPSWCReadMacId(PT_CPSW_INTERNAL pAdapter);
175 #ifdef TRACE
176 static void emllDumpFrame(EC_T_BOOL bTxFrame, EC_T_BYTE *pbyFrame, EC_T_DWORD dwSize);
177 #endif
179 /***************************************************************************************************
180 * GLOBALS
181 */
183 /***************************************************************************************************
184 * LOCALS
185 */
186 static PT_CPSW_INTERNAL S_oOpenInstanceRoot;
187 static EC_T_INT S_nOpenedInstances;
189 /***************************************************************************************************
190 * HELPER FUNCTIONS
191 */
193 static inline EC_T_DWORD dma_va2pa(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD virtaddr)
194 {
195 return pAdapter->dwDMAPa + (virtaddr - pAdapter->dwDMAVa);
196 }
198 static inline EC_T_DWORD dmadtor_va2pa(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD virtaddr)
199 {
200 return pAdapter->dwDmaDtorBasePa + (virtaddr - (EC_T_DWORD) pAdapter->pDmaDtorBase);
201 }
203 static inline EC_T_DWORD dma_pa2va(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD physaddr)
204 {
205 return pAdapter->dwDMAVa + (physaddr - pAdapter->dwDMAPa);
206 }
208 static inline EC_T_DWORD dmadtor_pa2va(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD physaddr)
209 {
210 return (EC_T_DWORD) pAdapter->pDmaDtorBase + (physaddr - pAdapter->dwDmaDtorBasePa);
211 }
213 #if (defined INSTRUMENT_LL)
214 #include <LinkOsMock.h>
215 #define w32(reg, val) LinkOsMock::RegWrite32(reg, val)
216 #define r32(reg) LinkOsMock::RegRead32(reg)
217 #else
219 inline void w32(volatile EC_T_DWORD* addr, EC_T_DWORD val)
220 {
221 LinkOsMemoryBarrier();
222 *addr = val;
223 }
225 inline EC_T_DWORD r32(volatile EC_T_DWORD* addr)
226 {
227 EC_T_DWORD val = *addr;
228 LinkOsMemoryBarrier();
229 return val;
230 }
231 #endif
233 static inline void CPSWFreeBuffer(T_CPSW_BUFENTRY *pBuf)
234 {
235 pBuf->eBufState = BS_FREE;
236 }
238 static EC_T_DWORD inline CPSWPortIdx(PT_CPSW_INTERNAL pAdapter)
239 {
240 /* dwInstance is 1-based but port index is 0-based */
241 return pAdapter->oInitParms.linkParms.dwInstance - 1;
242 }
244 static EC_T_VOID CPSWCopyInitParam(PT_CPSW_INTERNAL pAdapter, EC_T_LINK_PARMS_CPSW* pLinkParmsAdapter)
245 {
246 if (pLinkParmsAdapter->linkParms.dwSignature == EC_LINK_PARMS_SIGNATURE_CPSW_V1)
247 {
248 LinkOsMemcpy(&(pAdapter->oInitParms), pLinkParmsAdapter, sizeof(EC_T_LINK_PARMS_CPSW_V1));
250 // fill new fields
251 pAdapter->oInitParms.bNotUseDmaBuffers = EC_FALSE; /* use old behavior */
252 }
253 else
254 {
255 LinkOsMemcpy(&(pAdapter->oInitParms), pLinkParmsAdapter, sizeof(EC_T_LINK_PARMS_CPSW));
256 }
257 }
261 /***************************************************************************************************
262 * DRIVER API
263 */
265 /********************************************************************************/
266 /** \brief Open Link Layer connection.
267 *
268 * \return EC_E_NOERROR or error code.
269 */
270 static EC_T_DWORD EcLinkOpen
271 (
272 void* pvLinkParms, /* [in] link parameters */
273 EC_T_RECEIVEFRAMECALLBACK pfReceiveFrameCallback, /* [in] pointer to rx callback function */
274 EC_T_LINK_NOTIFY pfLinkNotifyCallback, /* [in] pointer to notification callback function */
275 void* pvContext, /* [in] caller context, to be used in callback functions */
276 void** ppvInstance /* [out] instance handle */
277 )
278 {
279 EC_T_DWORD dwRetVal = EC_E_ERROR;
280 EC_T_LINK_PARMS_CPSW *pLinkParmsAdapter = (EC_T_LINK_PARMS_CPSW*)pvLinkParms;
281 PT_CPSW_INTERNAL pAdapter = EC_NULL;
282 EC_T_DWORD dwRegisterBase = 0;
283 EC_T_DWORD dwOffs;
285 EC_UNREFPARM(pfLinkNotifyCallback);
287 /* check parameters */
288 if (EC_NULL == ppvInstance)
289 {
290 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): No memory for Driver Instance handle provided (ppvInstance may not be EC_NULL)!\n"));
291 dwRetVal = EC_E_INVALIDPARM;
292 goto Exit;
293 }
294 if (EC_NULL == pLinkParmsAdapter)
295 {
296 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Missing Configuration for CPSW Link Layer!\n"));
297 dwRetVal = EC_E_INVALIDPARM;
298 goto Exit;
299 }
300 if (EC_LINK_PARMS_SIGNATURE_CPSW != pLinkParmsAdapter->linkParms.dwSignature
301 && EC_LINK_PARMS_SIGNATURE_CPSW_V1 != pLinkParmsAdapter->linkParms.dwSignature)
302 {
303 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Invalid Configuration for CPSW Link Layer!\n"));
304 dwRetVal = EC_E_INVALIDPARM;
305 goto Exit;
306 }
307 if (EcLinkMode_INTERRUPT == pLinkParmsAdapter->linkParms.eLinkMode)
308 {
309 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): interrupt mode not supported!\n"));
310 dwRetVal = EC_E_INVALIDPARM;
311 goto Exit;
312 }
313 if ((pLinkParmsAdapter->linkParms.dwInstance < 1) || (pLinkParmsAdapter->linkParms.dwInstance > 2))
314 {
315 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Instance must be 1 or 2!\n"));
316 dwRetVal = EC_E_INVALIDPARM;
317 goto Exit;
318 }
319 if (pLinkParmsAdapter->dwPortPrio != 0 && pLinkParmsAdapter->dwPortPrio != 1)
320 {
321 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Port priority must be 0 or 1!\n" ));
322 dwRetVal = EC_E_INVALIDPARM;
323 goto Exit;
324 }
326 /* create instance */
327 *ppvInstance = EC_NULL;
328 #if defined STARTERWARE_NOOS && defined ADAPTER_DESC_FROM_UC_MEM
329 pAdapter = (PT_CPSW_INTERNAL)(GetStartAddrDdrUc() + 0x100000);
330 DBG( "pAdapter from uncached ram at 0x%x\n", (EC_T_DWORD)pAdapter );
331 #else
332 pAdapter = (PT_CPSW_INTERNAL) LinkOsMalloc(sizeof(T_CPSW_INTERNAL));
333 #endif
335 LinkOsMemset(pAdapter, 0, sizeof(T_CPSW_INTERNAL));
336 CPSWCopyInitParam(pAdapter, pLinkParmsAdapter);
338 pAdapter->oInitParms.dwPhyAddr &= 0x1F; // 0 .. 31
339 pAdapter->dwRxDmaChan = PRI2DMACHAN(pAdapter->oInitParms.dwPortPrio);
340 pAdapter->dwTxDmaChanCyc = pAdapter->dwRxDmaChan & (~1);
341 pAdapter->dwTxDmaChanAcyc = pAdapter->dwRxDmaChan | 1;
342 pAdapter->dwTxDmaChan = pAdapter->dwTxDmaChanCyc;
344 if (!ListCanAddAdapter(pAdapter))
345 {
346 SYS_ERRORMSG(("CPSW-EcLinkOpen(): Instance already in use!!\n"));
347 dwRetVal = EC_E_INVALIDPARM;
348 goto Exit;
349 }
351 pAdapter->dwLosalHandle = LinkOsOpen();
353 if (pAdapter->oInitParms.bMaster)
354 {
355 // Set PIN MUX / Enable Clocks
356 LinkOsPlatformInit();
357 #ifdef CPSW_ENABLE_CLOCKS
358 CPSWClkEnable(pAdapter);
359 #endif
360 }
362 CPSWCReadMacId(pAdapter); // Read MAC-ID from EFUSE
364 INF( "Port %d, Prio %d, Flags [%s] [%s], MAC %02x:%02x:%02x:%02x:%02x:%02x\n\n",
365 pLinkParmsAdapter->linkParms.dwInstance,
366 pLinkParmsAdapter->dwPortPrio,
367 (pLinkParmsAdapter->linkParms.eLinkMode == EcLinkMode_INTERRUPT) ? "Interrupt" : "Polling",
368 pLinkParmsAdapter->bMaster ? "Master" : "Slave",
369 pAdapter->abyStationAddress[0], pAdapter->abyStationAddress[1], pAdapter->abyStationAddress[2],
370 pAdapter->abyStationAddress[3], pAdapter->abyStationAddress[4], pAdapter->abyStationAddress[5]);
372 // Map 32k register file
373 if (CPSWMapMemory(pAdapter,
374 pAdapter->oInitParms.oPlatCfg.dwRegisterBase, &dwRegisterBase) != EC_E_NOERROR)
375 {
376 dwRetVal = EC_E_NOMEMORY;
377 goto Exit;
378 }
380 pAdapter->dwRegisterBase = dwRegisterBase;
381 CPSWMapRegisterSet(pAdapter);
383 /* configure new instance */
385 pAdapter->dwSignature = EC_LINK_PARMS_SIGNATURE_CPSW;
386 pAdapter->pfReceiveFrameCallback = pfReceiveFrameCallback;
387 pAdapter->pvCallbackContext = pvContext;
389 /* fill IRQ Parms */
390 pAdapter->oIrqParms.pvAdapter = (void *) pAdapter;
391 pAdapter->oIrqParms.dwSysIrq = pAdapter->oInitParms.dwRxInterrupt;
392 pAdapter->oIrqParms.pfIrqOpen = EcLinkIrqOpen;
393 pAdapter->oIrqParms.pfIrqClose = EcLinkIrqClose;
394 pAdapter->oIrqParms.pfIrqAckAll = EcLinkIrqAck;
395 pAdapter->oIrqParms.pvLOSALContext = EC_NULL; /* Initialized by LOSAL */
396 pAdapter->oIrqParms.dwIstPriority = pLinkParmsAdapter->linkParms.dwIstPriority;
397 pAdapter->oIrqParms.dwIstStackSize = 0x4000; /* IST Thread Stack size */
398 pAdapter->oIrqParms.pfIstFunction = DoHandleInterrupt;
399 pAdapter->oIrqParms.pfIsrFunction = EC_NULL;
400 pAdapter->oIrqParms.pvIsrFuncCtxt = EC_NULL;
401 pAdapter->oIrqParms.eIntSource = INTSOURCE_INTERNAL; /* no PCI */
403 #if defined COPY_FRAME
404 pAdapter->dwRxCachedBufferSize = CPSW_RXCACHEDBUFCNT * CPSW_RXBUFLEN;
405 pAdapter->dwTxCachedBufferSize = CPSW_TXCACHEDBUFCNT * CPSW_TXBUFLEN;
407 pAdapter->dwTxCachedBufferSize += CACHELINE_SIZE;
408 pAdapter->dwRxCachedBufferSize += CACHELINE_SIZE;
410 pAdapter->pRxCachedBuffer = (EC_T_BYTE *) LinkOsMalloc(pAdapter->dwRxCachedBufferSize);
411 pAdapter->pTxCachedBuffer = (EC_T_BYTE *) LinkOsMalloc(pAdapter->dwTxCachedBufferSize);
413 if (pAdapter->pRxCachedBuffer == EC_NULL || pAdapter->pTxCachedBuffer == EC_NULL)
414 {
415 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Error Alloc Buffer memory\n"));
416 dwRetVal = EC_E_NOMEMORY;
417 goto Exit;
418 }
420 pAdapter->pRxCachedBufferOriginal = pAdapter->pRxCachedBuffer;
421 pAdapter->pTxCachedBufferOriginal = pAdapter->pTxCachedBuffer;
423 pAdapter->pRxCachedBuffer = (EC_T_BYTE*)CPSW_CACHE_UP((EC_T_DWORD)pAdapter->pRxCachedBuffer);
424 pAdapter->pTxCachedBuffer = (EC_T_BYTE*)CPSW_CACHE_UP((EC_T_DWORD)pAdapter->pTxCachedBuffer);
426 #endif
428 //
429 // Setup DMA
430 //
432 pAdapter->dwTxDescSize = sizeof(T_CPSW_DESC) * CPSW_TXDESCNT;
433 pAdapter->dwRxDescSize = sizeof(T_CPSW_DESC) * CPSW_RXDESCNT;
434 pAdapter->dwTxBufferSize = CPSW_TXDMABUFCNT * CPSW_TXBUFLEN;
435 pAdapter->dwRxBufferSize = CPSW_RXDMABUFCNT * CPSW_RXBUFLEN;
436 pAdapter->dwDMASize = 0;
438 // RX Data buffers (each 2k)
439 pAdapter->dwDMASize += pAdapter->dwRxBufferSize;
440 // TX Data buffers (each 2k)
441 pAdapter->dwDMASize += pAdapter->dwTxBufferSize;
442 #ifndef USE_CPPI_RAM
443 // Align this space (needed by CPSW)
444 pAdapter->dwDMASize = CPSW_DMA_ALIGN(pAdapter->dwDMASize);
445 // RX Descriptors
446 pAdapter->dwDMASize += pAdapter->dwRxDescSize;
447 // TX Descriptors
448 pAdapter->dwDMASize += pAdapter->dwTxDescSize;
449 #endif
451 // Add one extra page then align to next page boundary
452 pAdapter->dwDMASize += CPSW_PAGE_SIZE;
453 pAdapter->dwDMASize = PAGE_UP(pAdapter->dwDMASize);
455 // Allocate DMA memory
456 LinkOsAllocDmaBuffer(
457 &pAdapter->oAdapterObject,
458 (EC_T_BYTE **)&pAdapter->dwDMAVa,
459 (EC_T_BYTE **)&pAdapter->dwDMAUncachedVa,
460 (EC_T_BYTE **)&pAdapter->dwDMAPa,
461 pAdapter->dwDMASize );
463 if ( pAdapter->dwDMAVa == EC_NULL )
464 {
465 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Error Mapping DMA memory\n"));
466 dwRetVal = EC_E_NOMEMORY;
467 goto Exit;
468 }
470 DBG("DMA buffer from uncached ram at 0x%x\n", pAdapter->dwDMAVa);
472 // Make sure that start address is page aligned
473 pAdapter->dwDMAOffset = PAGE_UP(pAdapter->dwDMAVa) - pAdapter->dwDMAVa;
474 pAdapter->dwDMAVa += pAdapter->dwDMAOffset;
475 pAdapter->dwDMAPa += pAdapter->dwDMAOffset;
476 pAdapter->dwDMASize -= pAdapter->dwDMAOffset;
478 // Initialize DMA space with zeros
479 LinkOsMemset(pAdapter->dwDMAVa, 0, pAdapter->dwDMASize);
481 // Store address of RX buffers
482 pAdapter->pRxBuffer = (EC_T_BYTE *) pAdapter->dwDMAVa;
484 // Store address of TX buffers
485 pAdapter->pTxBuffer = (EC_T_BYTE *) pAdapter->pRxBuffer + pAdapter->dwRxBufferSize;
487 #ifdef USE_CPPI_RAM
488 dwOffs = CPSWPortIdx(pAdapter) * CPSW_PORTDMA_LENGTH;
489 pAdapter->pDmaDtorBase = (T_CPSW_DESC *) ((EC_T_DWORD) pAdapter->regs.BdRam + dwOffs);
490 pAdapter->dwDmaDtorBasePa = pAdapter->oInitParms.oPlatCfg.dwRegisterBase +
491 pAdapter->oInitParms.oPlatCfg.dwBdRamOffs + dwOffs;
492 LinkOsMemset((EC_T_BYTE *) pAdapter->pDmaDtorBase, 0, CPSW_PORTDMA_LENGTH);
493 #else
494 EC_UNREFPARM(dwOffs);
495 pAdapter->pDmaDtorBase = (T_CPSW_DESC *) CPSW_DMA_ALIGN((EC_T_DWORD) pAdapter->pTxBuffer + pAdapter->dwTxBufferSize);
496 pAdapter->dwDmaDtorBasePa = dma_va2pa(pAdapter, (EC_T_DWORD) pAdapter->pDmaDtorBase);
497 #endif
499 // Store address of RX descriptors
500 pAdapter->pRxDesc = pAdapter->pDmaDtorBase;
502 // Store address of TX descriptors
503 pAdapter->pTxDesc = (T_CPSW_DESC *) ((EC_T_DWORD) pAdapter->pDmaDtorBase + pAdapter->dwRxDescSize);
505 DBG("VirtAddr: RegBase 0x%08x, DmaDtorBase 0x%08x, DmaBase 0x%08x\n",
506 pAdapter->dwRegisterBase,
507 pAdapter->pDmaDtorBase,
508 pAdapter->dwDMAVa);
509 DBG("PhysAddr: RegBase 0x%08x, DmaDtorBase 0x%08x, DmaBase 0x%08x\n",
510 pAdapter->oInitParms.oPlatCfg.dwRegisterBase,
511 pAdapter->dwDmaDtorBasePa,
512 pAdapter->dwDMAPa);
514 // initialize RX buffer from the heap
515 if (pAdapter->oInitParms.bNotUseDmaBuffers)
516 {
517 dwRetVal = pAdapter->rxBuffers.Initialize(CPSW_RXDMABUFCNT, CPSW_RXBUFLEN);
518 if (EC_E_NOERROR != dwRetVal)
519 goto Exit;
520 }
522 LinkOsInterruptDisable(&pAdapter->oIrqParms);
524 if (pAdapter->oInitParms.bMaster)
525 {
526 CPSWReset(pAdapter); // Reset chip
527 CPSWCheckId(pAdapter); // Print ID info
528 }
530 // Make sure that the DMA is stopped (An previously instance may have gone
531 // without calling CPSWTeardown() on LL close.
532 // Teardown may set the teardown bit in the (old) DMA dtor if present.
533 // -> Make sure RX DMA dtors are initialized after teardown!
534 CPSWTeardown(pAdapter);
536 CPSWSetupBuffers(pAdapter);
537 CPSWSetupRxDtors(pAdapter);
538 CPSWSetupTxDtors(pAdapter);
540 CPSWInitializeHardware(pAdapter);
542 // Initialize IRQ if desired
543 if ( EcLinkMode_INTERRUPT == pAdapter->oInitParms.linkParms.eLinkMode )
544 {
545 if (! LinkOsInterruptInitialize(&pAdapter->oIrqParms))
546 {
547 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Cannot Initialize interrupt\n"));
548 dwRetVal = EC_E_ERROR;
549 goto Exit;
550 }
551 }
553 // enqueue adapter
554 ListAddOI(pAdapter);
556 // increment instance counter
557 S_nOpenedInstances++;
559 // return "handle"
560 *ppvInstance = pAdapter;
562 // no errors
563 dwRetVal = EC_E_NOERROR;
565 Exit:
567 if (EC_E_NOERROR != dwRetVal && EC_E_INVALIDSTATE != dwRetVal)
568 {
569 if (EC_NULL != pAdapter)
570 {
571 EcLinkClose(pAdapter);
572 }
573 }
575 return dwRetVal;
576 }
578 /*****************************************************************************/
579 /** \brief Verifies adapter is correct (not null and type is CPSW).
580 */
581 static inline EC_T_BOOL IsCorrectAdapter(PT_CPSW_INTERNAL pAdapter)
582 {
583 if (EC_NULL == pAdapter || pAdapter->dwSignature != EC_LINK_PARMS_SIGNATURE_CPSW)
584 {
585 return EC_FALSE;
586 }
587 return EC_TRUE;
588 }
590 /********************************************************************************/
591 /** \brief Close Link Layer connection.
592 *
593 * \return EC_E_NOERROR or error code.
594 */
595 static EC_T_DWORD EcLinkClose(
596 void* pvInstance /* [in] instance handle */
597 )
598 {
599 EC_T_DWORD dwRetVal = EC_E_ERROR;
600 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL) pvInstance;
602 #if defined DEBUG
603 // check for Type Signature */
604 if (EC_NULL == pAdapter || pAdapter->dwSignature != EC_LINK_PARMS_SIGNATURE_CPSW)
605 {
606 dwRetVal = EC_E_INVALIDPARM;
607 goto Exit;
608 }
609 #endif
611 if ( EcLinkMode_INTERRUPT == pAdapter->oInitParms.linkParms.eLinkMode )
612 {
613 // Disable interrupt
614 LinkOsInterruptDisable( &pAdapter->oIrqParms );
615 }
617 // Shutdown RX+TX for the current channel
618 CPSWTeardown(pAdapter);
620 // Free DMA memory
621 if (pAdapter->dwDMAVa != 0)
622 {
623 if (pAdapter->oInitParms.bNotUseDmaBuffers)
624 {
625 pAdapter->rxBuffers.Deinitialize();
626 }
628 pAdapter->dwDMAVa -= pAdapter->dwDMAOffset;
629 pAdapter->dwDMASize += pAdapter->dwDMAOffset;
630 pAdapter->dwDMAPa -= pAdapter->dwDMAOffset;
632 LinkOsFreeDmaBuffer(
633 &pAdapter->oAdapterObject,
634 (EC_T_BYTE *)pAdapter->dwDMAPa,
635 (EC_T_BYTE *)pAdapter->dwDMAVa,
636 (EC_T_BYTE *)pAdapter->dwDMAUncachedVa,
637 pAdapter->dwDMASize );
639 pAdapter->dwDMAPa = 0;
640 pAdapter->dwDMAVa = 0;
641 }
643 // Unmap IO memory
644 if (pAdapter->dwRegisterBase != 0)
645 {
646 LinkOsUnmapMemory((EC_T_BYTE *)pAdapter->dwRegisterBase, CPSW_IO_LENGTH);
647 }
649 #if defined COPY_FRAME
650 if (pAdapter->pRxCachedBufferOriginal != EC_NULL)
651 {
652 LinkOsFree(pAdapter->pRxCachedBufferOriginal);
653 pAdapter->pRxCachedBuffer = EC_NULL;
654 pAdapter->pRxCachedBufferOriginal = EC_NULL;
655 }
657 if (pAdapter->pTxCachedBufferOriginal != EC_NULL)
658 {
659 LinkOsFree(pAdapter->pTxCachedBufferOriginal);
660 pAdapter->pTxCachedBuffer = EC_NULL;
661 pAdapter->pTxCachedBufferOriginal = EC_NULL;
662 }
663 #endif
665 LinkOsClose();
667 // Remove adapter instance from instance-list
668 ListRmOI(pAdapter);
669 S_nOpenedInstances--;
671 #if defined STARTERWARE_NOOS && defined ADAPTER_DESC_FROM_UC_MEM
672 #else
673 LinkOsFree(pAdapter);
674 #endif
676 dwRetVal = EC_E_NOERROR;
677 goto Exit;
679 Exit:
680 return dwRetVal;
681 }
683 #ifdef DEBUG
684 static void DumpDtor(PT_CPSW_INTERNAL pAdapter, volatile T_CPSW_DESC *pDesc)
685 {
686 PRINT("PA 0x%x, Next 0x%x, Buf 0x%x, Len 0x%x, Mode 0x%x [%s %s %s %s]\n",
687 dmadtor_va2pa(pAdapter, (EC_T_DWORD)pDesc),
688 pDesc->dwNext,
689 pDesc->dwBuffer,
690 pDesc->dwLen,
691 pDesc->dwMode,
692 (pDesc->dwMode & CPDMA_DESC_SOP) ? "SOP" : "",
693 (pDesc->dwMode & CPDMA_DESC_EOP) ? "EOP" : "",
694 (pDesc->dwMode & CPDMA_DESC_OWNER) ? "OWN" : "",
695 (pDesc->dwMode & CPDMA_DESC_EOQ) ? "EOQ" : ""
696 );
697 }
698 #endif // ifdef DEBUG
700 static void DumpTxDtors(PT_CPSW_INTERNAL pAdapter, const char *id)
701 {
702 #ifdef DEBUG
703 PCPSW_REGSET regs = &pAdapter->regs;
704 PRINT("TX Dtors (%s): DMA-Status 0x%x, CP 0x%0x, HDP 0x%x, PA[N] 0x%x, PA[N-1] 0x%x\n",
705 id,
706 R32(regs->Dma->DMAStatus),
707 R32(regs->StateRam->Tx_CP[pAdapter->dwTxDmaChan]),
708 R32(regs->StateRam->Tx_HDP[pAdapter->dwTxDmaChan]),
709 dmadtor_va2pa(pAdapter, (EC_T_DWORD)TX_DESC_PTR(pAdapter->dwTxDescIdx)),
710 dmadtor_va2pa(pAdapter, (EC_T_DWORD)pAdapter->pTxTailDesc)
711 );
712 for (int i = 0; i < CPSW_TXDESCNT; ++i)
713 {
714 PRINT("Dtor %d: ", i);
715 DumpDtor(pAdapter, TX_DESC_PTR(i));
716 }
717 #else
718 EC_UNREFPARM(pAdapter);
719 EC_UNREFPARM(id);
720 #endif // ifdef DEBUG
721 }
723 static EC_T_DWORD CPSWWaitUntilTxDmaIsEmpty(PT_CPSW_INTERNAL pAdapter)
724 {
725 // Wait until any previous DMA has finished (HDP is set to 0 if TX-DMA-Channel goes idle).
726 // Workaround for an issue where appending to a running DMA-Q, the MAC runs to EOQ
727 // even though pTxDescTail EOQ-flag has been reset.
728 // This issue has been monitored for the shared User/Kernel CPSW-MAC mode under EC7.
730 EC_T_DWORD dwCnt = 0;
731 while (R32(pAdapter->regs.StateRam->Tx_HDP[pAdapter->dwTxDmaChan]))
732 {
733 LinkOsSysDelay(10);
734 dwCnt++;
735 if (dwCnt > 500000) // 500ms
736 {
737 ERR("DMA wait timeout\n");
738 DumpTxDtors(pAdapter, "DMA-Wait-Timeout");
740 return EC_E_NOMEMORY;
741 }
742 }
743 return EC_E_NOERROR;
744 }
746 #ifdef DEBUG
747 static EC_T_BOOL IsCorrectParamsForSendFrame(PT_CPSW_INTERNAL pAdapter,
748 EC_T_LINK_FRAMEDESC* pLinkFrameDesc)
749 {
750 T_CPSW_BUFENTRY* pBufEntry = (T_CPSW_BUFENTRY*)(pLinkFrameDesc->pbyFrame - CPSW_BUFENTRY_FRAME_OFFSET);
751 EC_T_BYTE* pBufMem = (EC_T_BYTE*)pBufEntry;
753 LinkOsDbgAssert((EC_T_DWORD)pBufMem == CPSW_CACHE_DOWN((EC_T_DWORD)pBufMem));
754 if (!IsCorrectAdapter(pAdapter))
755 {
756 return EC_FALSE;
757 }
759 /* Check if frame address was allocated from the DMA buffer pool */
760 if (
761 #ifdef COPY_FRAME
762 (pBufMem < pAdapter->pTxCachedBuffer)
763 || ((pBufMem + pLinkFrameDesc->dwSize) >(pAdapter->pTxCachedBuffer + pAdapter->dwTxCachedBufferSize))
764 #else
765 (pBufMem < pAdapter->pTxBuffer)
766 || ((pBufMem + pLinkFrameDesc->dwSize) < pAdapter->pTxBuffer)
767 || ((pBufMem + pLinkFrameDesc->dwSize) >(pAdapter->pTxBuffer + pAdapter->dwTxBufferSize))
768 #endif /* !COPY_FRAME */
769 || (pBufEntry->dwMagicKey != BUFFER_MAGIC_TX)
770 )
771 {
772 return EC_FALSE;
773 }
775 if (pLinkFrameDesc->dwSize < 60)
776 {
777 return EC_FALSE;
778 }
780 return EC_TRUE;
781 }
782 #endif /* DEBUG */
784 /*****************************************************************************/
785 /** \brief Send data frame
786 *
787 * \return EC_E_NOERROR or error code.
788 */
789 static EC_T_DWORD EcLinkSendFrameFromDma(
790 void* pvInstance,
791 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
792 )
793 {
794 EC_T_DWORD dwRetVal = EC_E_ERROR;
795 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL)pvInstance;
796 volatile T_CPSW_DESC* pTxDesc;
797 EC_T_DWORD txDescPa;
798 T_CPSW_BUFENTRY* pBufEntry = (T_CPSW_BUFENTRY*)(pLinkFrameDesc->pbyFrame - CPSW_BUFENTRY_FRAME_OFFSET);
799 EC_T_DWORD dwTmp, dwMode;
800 PCPSW_REGSET regs = &pAdapter->regs;
801 EC_T_DWORD dwDmaChan = pAdapter->dwTxDmaChan;
802 #ifdef COPY_FRAME
803 T_CPSW_FRAMEBUFENTRY* pTxBuf;
804 #endif
806 #ifdef DEBUG
807 if (!IsCorrectParamsForSendFrame(pAdapter, pLinkFrameDesc))
808 {
809 dwRetVal = EC_E_INVALIDPARM;
810 goto Exit;
811 }
812 #endif /* DEBUG */
814 #if !defined USE_CPSW_TEST
815 /* Overwrite the dst address with the Ethernet broadcast address. Our stack will use
816 the multicast address defined in the ENI as dst address.
817 We would need to retrieve this multicast address (e.g. by Master's ioctl) and then
818 setup an vlan/multicast ALE entry to recognize that address if the frame is received. */
819 for (int i = 0; i < MAC_ADDR_LEN; ++i) pLinkFrameDesc->pbyFrame[i] = 0xFF;
820 #endif
822 /* Lookup next free descriptor in descriptor ring buffer */
823 pTxDesc = TX_DESC_PTR(pAdapter->dwTxDescIdx);
825 /* If the current descriptor has the OWN bit set, then the corresponding buffer was not (already) processed by the NIC.
826 This means that the ring buffer write pointer (Host: dwTxDescIdx) has reached the read pointer (NIC: OWN bit) */
827 if (R32(pTxDesc->dwMode) & (CPDMA_DESC_OWNER))
828 {
829 ERR("EcLinkSendFrame: Owner bit set, tx buffer overflow?!\n");
830 DumpTxDtors(pAdapter, "TX-Buffer-Underun");
831 dwRetVal = EC_E_NOMEMORY;
832 goto Exit;
833 }
835 #if defined COPY_FRAME
836 pTxBuf = TX_DMABUF_PTR(pAdapter->dwTxDescIdx); /* Get DMA buffer: Tx Desc Idx == Tx Buffer Idx */
837 LinkOsMemcpy(pTxBuf->pFrame, pLinkFrameDesc->pbyFrame, pLinkFrameDesc->dwSize); /* Copy cached buffer to DMA buffer */
838 CPSWFreeBuffer(pBufEntry); /* Free buffer from cached pool */
839 pBufEntry = &pTxBuf->bufentry; /* pBufEntry now points to the DMA buffer */
840 #endif
842 /* Assign descriptor index to the management object for the send buffer */
843 pBufEntry->dwDescIdx = pAdapter->dwTxDescIdx;
844 /* Mark buffer as used for DMA transfer */
845 pBufEntry->eBufState = BS_DMA_STARTED;
846 /* Debugging helper */
847 pBufEntry->dwFrameLen = pLinkFrameDesc->dwSize & CPDMA_BUFLEN_MASK;
849 /* Prepare descriptor for send */
850 W32(pTxDesc->dwNext, 0);
851 #if defined COPY_FRAME
852 LinkOsDbgAssert((EC_T_DWORD) pTxBuf->pFrame == CPSW_CACHE_DOWN((EC_T_DWORD) pTxBuf->pFrame));
853 #else
854 LinkOsDbgAssert((EC_T_DWORD)pLinkFrameDesc->pbyFrame == CPSW_CACHE_DOWN((EC_T_DWORD)pLinkFrameDesc->pbyFrame));
856 /* Write cache lines back to memory */
857 LinkOsCacheDataSync(pLinkFrameDesc->pbyFrame,
858 dma_va2pa(pAdapter, (EC_T_DWORD) pLinkFrameDesc->pbyFrame),
859 CPSW_CACHE_UP(pLinkFrameDesc->dwSize));
861 W32(pTxDesc->dwBuffer, dma_va2pa(pAdapter, (EC_T_DWORD) pLinkFrameDesc->pbyFrame));
862 #endif
863 W32(pTxDesc->dwLen, pLinkFrameDesc->dwSize & CPDMA_BUFLEN_MASK);
864 dwTmp = (pLinkFrameDesc->dwSize & CPDMA_BUFLEN_MASK)
865 | CPDMA_DESC_SOP | CPDMA_DESC_EOP | CPDMA_DESC_OWNER | CPDMA_DESC_PORTEN;
866 dwTmp |= (pAdapter->oInitParms.linkParms.dwInstance) << CPDMA_DESC_PORTSHIFT; /* Directed send to port */
867 W32(pTxDesc->dwMode, dwTmp);
869 txDescPa = dmadtor_va2pa(pAdapter, (EC_T_DWORD) pTxDesc);
871 _TRC("Read HDPPhys[%d] 0x%08x\n", dwDmaChan, R32(regs->StateRam->Tx_HDP[dwDmaChan]));
873 if (pAdapter->bGatherFrames)
874 {
875 if (!pAdapter->pTxHeadDesc)
876 pAdapter->pTxHeadDesc = pTxDesc;
878 if (pAdapter->pTxTailDesc)
879 {
880 volatile T_CPSW_DESC *pTxDescTail = pAdapter->pTxTailDesc;
881 W32(pTxDescTail->dwNext, txDescPa); /* Append dtor to the tail */
882 }
883 }
884 else
885 {
886 if (pAdapter->pTxTailDesc == EC_NULL) /* First send after adapter reset / initialization */
887 {
888 TRC("TX Init HDP[%d] with 0x%08x\n", dwDmaChan, txDescPa);
889 W32(regs->StateRam->Tx_HDP[dwDmaChan], txDescPa);
890 }
891 else
892 {
893 volatile T_CPSW_DESC *pTxDescTail = pAdapter->pTxTailDesc;
894 W32(pTxDescTail->dwNext, txDescPa); /* Append dtor to the tail */
896 #ifdef _WIN32_WCE
897 if (EC_E_NOERROR != (dwRetVal = CPSWWaitUntilTxDmaIsEmpty(pAdapter)))
898 goto Exit;
899 #endif /* _WIN32_WCE */
901 /* If the DMA engine, already reached the end of the chain,
902 the EOQ will be set. In that case, the HDP shall be written again. */
903 dwMode = R32(pTxDescTail->dwMode);
904 if ((dwMode & (CPDMA_DESC_EOQ | CPDMA_DESC_OWNER)) == CPDMA_DESC_EOQ)
905 {
906 TRC("TX EOQ HDP[%d] reinit with 0x%08x\n", dwDmaChan, txDescPa);
907 W32(pTxDescTail->dwMode, dwMode & ~CPDMA_DESC_EOQ); /* Clear EOQ */
908 W32(regs->StateRam->Tx_HDP[dwDmaChan], txDescPa); /* Restart DMA */
909 }
910 }
911 dwTmp = R32(regs->StateRam->Tx_HDP[dwDmaChan]);
912 }
914 pAdapter->pTxTailDesc = pTxDesc;
916 /* Increment ring buffer pointer */
917 pAdapter->dwTxDescIdx = NEXT_TX_DESC_IDX(pAdapter->dwTxDescIdx);
919 /* immediate after sending packet do timestamping */
920 if (EC_NULL != pLinkFrameDesc->pfnTimeStamp)
921 {
922 *pLinkFrameDesc->pdwLastTSResult = pLinkFrameDesc->pfnTimeStamp(pLinkFrameDesc->pvTimeStampCtxt, pLinkFrameDesc->pdwTimeStampLo);
923 *pLinkFrameDesc->pdwTimeStampPostLo = *pLinkFrameDesc->pdwTimeStampLo;
924 }
926 /* no errors */
927 dwRetVal = EC_E_NOERROR;
929 _TRC("Write DescPhys 0x%08x, DescVirt 0x%08x, HDPPhys[%d] 0x%08x\n",
930 txDescPa,
931 (EC_T_DWORD) pTxDesc,
932 dwDmaChan, dwTmp);
934 #if defined TRACE && 0
935 TRC("TX buffer send %d, Size %d\n", pAdapter->dwTxDescIdx + 1, pLinkFrameDesc->dwSize);
936 emllDumpFrame(EC_TRUE, pLinkFrameDesc->pbyFrame, pLinkFrameDesc->dwSize);
937 /* wait until send and read result memory */
938 LinkOsSleep(100);
939 TRC("pTxDesc 0x%08x, TxDescPa 0x%08x, HDP[%d] 0x%08x, Next 0x%08x, Buffer 0x%08x, Len 0x%08x, Mode 0x%08x\n",
940 (EC_T_DWORD)pTxDesc,
941 dmadtor_va2pa(pAdapter, (EC_T_DWORD) pTxDesc),
942 dwDmaChan, dwTmp,
943 R32(pTxDesc->dwNext),
944 R32(pTxDesc->dwBuffer),
945 R32(pTxDesc->dwLen),
946 R32(pTxDesc->dwMode));
947 #endif
949 Exit:
951 return dwRetVal;
952 }
954 /*****************************************************************************/
955 /** \brief Send data frame
956 *
957 * \return EC_E_NOERROR or error code.
958 */
959 static EC_T_DWORD EcLinkSendFrame(
960 void* pvInstance,
961 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
962 )
963 {
964 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL)pvInstance;
966 #if defined DEBUG
967 if (!IsCorrectAdapter(pAdapter) || EC_NULL == pLinkFrameDesc)
968 {
969 return EC_E_INVALIDPARM;
970 }
971 #endif
973 if (!pAdapter->oInitParms.bNotUseDmaBuffers)
974 {
975 return EcLinkSendFrameFromDma(pvInstance, pLinkFrameDesc);
976 }
977 else
978 {
979 EC_T_BYTE* pbyFrame = pLinkFrameDesc->pbyFrame;
980 EC_T_DWORD dwSize = pLinkFrameDesc->dwSize;
982 EC_T_DWORD dwRetVal = EcLinkAllocSendFrameFromDma(pAdapter, pLinkFrameDesc, pLinkFrameDesc->dwSize);
983 if (EC_E_NOERROR == dwRetVal)
984 {
985 // copy frame
986 OsMemcpy(pLinkFrameDesc->pbyFrame, pbyFrame, dwSize);
988 dwRetVal = EcLinkSendFrameFromDma(pvInstance, pLinkFrameDesc);
990 // restore members
991 pLinkFrameDesc->pbyFrame = pbyFrame;
992 pLinkFrameDesc->dwSize = dwSize;
993 }
995 return dwRetVal;
996 }
997 }
1000 /********************************************************************************/
1001 /** \brief Send data frame and free the frame buffer. This function must be
1002 * supported if EcLinkAllocSendFrame() is supported
1003 *
1004 * \return EC_E_NOERROR or error code.
1005 */
1006 static EC_T_DWORD EcLinkSendAndFreeFrame(
1007 void* pvInstance,
1008 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
1009 )
1010 {
1011 EC_T_DWORD dwRetVal = EC_E_ERROR;
1013 /* free-ing of buffers and descriptors is done during EcLinkAllocSendFrame so
1014 * calling the send routine is enough */
1015 dwRetVal = EcLinkSendFrame(pvInstance, pLinkFrameDesc);
1017 /* nothing to do */
1018 return dwRetVal;
1019 }
1021 /********************************************************************************/
1022 /** \brief Poll for received frame from DMA memory
1023 *
1024 * \return EC_E_NOERROR or error code.
1025 */
1026 static EC_T_DWORD EcLinkRecvFrameFromDma(
1027 PT_CPSW_INTERNAL pAdapter,
1028 EC_T_LINK_FRAMEDESC* pLinkFrameDesc) /* [in] link frame descriptor */
1029 {
1030 EC_T_DWORD dwRetVal = EC_E_ERROR;
1031 volatile T_CPSW_DESC* pRxDesc;
1032 EC_T_DWORD dwRxDescPa;
1033 PCPSW_REGSET regs = &pAdapter->regs;
1034 EC_T_DWORD dwMode;
1035 EC_T_DWORD dwDmaChan;
1037 // Lookup next descriptor and assigned buffer
1038 pRxDesc = RX_DESC_PTR(pAdapter->dwRxDescIdx);
1039 dwRxDescPa = dmadtor_va2pa(pAdapter, (EC_T_DWORD) pRxDesc);
1041 dwDmaChan = pAdapter->dwRxDmaChan;
1042 #if defined TRACE && 0
1043 TRC("\npRxDesc 0x%08x, RxDescPa 0x%08x, HDP[%d] 0x%08x, Next 0x%08x, Buffer 0x%08x, Len 0x%08x, Mode 0x%08x\n\n",
1044 (EC_T_DWORD)pRxDesc,
1045 dwRxDescPa,
1046 dwDmaChan, R32(regs->StateRam->Rx_HDP[dwDmaChan]),
1047 R32(pRxDesc->dwNext),
1048 R32(pRxDesc->dwBuffer),
1049 R32(pRxDesc->dwLen),
1050 R32(pRxDesc->dwMode));
1052 // Dump dtors
1053 for (int i = 0; i < CPSW_RXDESCNT; ++i)
1054 {
1055 volatile T_CPSW_DESC* pTmpDesc = RX_DESC_PTR(i);
1056 TRC("Desc[%d] 0x%08x, RxDescPa 0x%08x, HDP[%d] 0x%08x, Next 0x%08x, Buffer 0x%08x, Len 0x%08x, Mode 0x%08x\n",
1057 i,
1058 (EC_T_DWORD)pTmpDesc,
1059 dmadtor_va2pa(pAdapter, (EC_T_DWORD) pTmpDesc),
1060 dwDmaChan, R32(regs->StateRam->Rx_HDP[dwDmaChan]),
1061 R32(pTmpDesc->dwNext),
1062 R32(pTmpDesc->dwBuffer),
1063 R32(pTmpDesc->dwLen),
1064 R32(pTmpDesc->dwMode));
1065 }
1066 #endif
1068 dwMode = R32(pRxDesc->dwMode);
1069 if (! (dwMode & CPDMA_DESC_OWNER) ) // OWN Bit clear?
1070 {
1071 volatile T_CPSW_DESC* pRxDescTail;
1072 T_CPSW_FRAMEBUFENTRY* pBufEntry = EC_NULL;
1073 T_CPSW_BUFENTRY* pTmpBufEntry = EC_NULL;
1074 T_CPSW_FRAMEBUFENTRY* pFreeBufEntry = EC_NULL;
1076 pTmpBufEntry = (T_CPSW_BUFENTRY *)dma_pa2va(pAdapter, R32(pRxDesc->dwBuffer));
1077 pBufEntry = (T_CPSW_FRAMEBUFENTRY *)((EC_T_BYTE *) pTmpBufEntry - CPSW_BUFENTRY_FRAME_OFFSET);
1079 LinkOsDbgAssert(pBufEntry->bufentry.dwMagicKey == BUFFER_MAGIC_RX);
1081 pFreeBufEntry = CPSWAllocRxBuffer(pAdapter);
1082 if (pFreeBufEntry == EC_NULL) // All buffers used?
1083 {
1084 ERR("Out of RX buffers\n");
1085 dwRetVal = EC_E_NOMEMORY;
1086 goto Exit;
1087 }
1089 // Get frame pointer and frame size
1090 pLinkFrameDesc->dwSize = dwMode & CPDMA_BUFLEN_MASK;
1092 LinkOsDbgAssert( (EC_T_DWORD)pBufEntry->pFrame == CPSW_CACHE_DOWN((EC_T_DWORD)pBufEntry->pFrame) );
1094 // Invalidate cachelines
1095 LinkOsCacheDataInvalidateBuff(pBufEntry->pFrame,
1096 dma_va2pa(pAdapter, (EC_T_DWORD) pBufEntry->pFrame),
1097 CPSW_CACHE_UP(pLinkFrameDesc->dwSize));
1099 #if defined COPY_FRAME
1100 OsMemcpy(pFreeBufEntry->pFrame, pBufEntry->pFrame, pLinkFrameDesc->dwSize);
1101 pLinkFrameDesc->pbyFrame = pFreeBufEntry->pFrame;
1102 #else
1103 pLinkFrameDesc->pbyFrame = pBufEntry->pFrame;
1104 #endif
1106 // Prepare descriptor so that the NIC can reuse this descriptor for DMA transfer
1107 W32(pRxDesc->dwNext, 0);
1108 #if !defined COPY_FRAME
1110 // Invalidate cache lines
1111 LinkOsCacheDataInvalidateBuff(pFreeBufEntry->pFrame,
1112 dma_va2pa(pAdapter, (EC_T_DWORD) pFreeBufEntry->pFrame),
1113 CPSW_CACHE_UP(CPSW_RXBUFLEN - CACHELINE_SIZE));
1115 W32(pRxDesc->dwBuffer, dma_va2pa(pAdapter, (EC_T_DWORD) pFreeBufEntry->pFrame));
1116 #endif
1117 W32(pRxDesc->dwLen, CPDMA_RXBUFLEN);
1118 W32(pRxDesc->dwMode, CPDMA_DESC_OWNER | CPDMA_RXBUFLEN); // descriptor owned by MAC
1120 // Link dtor
1121 pRxDescTail = pAdapter->pRxTailDesc;
1122 W32(pRxDescTail->dwNext, dwRxDescPa);
1124 // If the DMA engine, already reached the end of the chain,
1125 // the EOQ will be set. In that case, the HDP shall be written again.
1126 dwMode = R32(pRxDescTail->dwMode);
1127 if ((dwMode & (CPDMA_DESC_EOQ | CPDMA_DESC_OWNER)) == CPDMA_DESC_EOQ)
1128 {
1129 TRC("RX EOQ HDP[%d] reinit with 0x%08x\n", dwDmaChan, dwRxDescPa);
1130 W32(pRxDescTail->dwMode, dwMode & ~CPDMA_DESC_EOQ); // Clear EOQ
1131 W32(regs->StateRam->Rx_HDP[dwDmaChan], dwRxDescPa); // Restart DMA
1132 }
1134 #if defined TRACE && 0
1135 TRC("RX buffer recv %d, Size %d\n", pAdapter->dwRxDescIdx + 1, pLinkFrameDesc->dwSize);
1136 emllDumpFrame(EC_FALSE, pLinkFrameDesc->pbyFrame, pLinkFrameDesc->dwSize);
1137 #endif
1139 pAdapter->pRxTailDesc = pRxDesc;
1141 // Increment descriptor ring buffer pointer
1142 pAdapter->dwRxDescIdx = NEXT_RX_DESC_IDX(pAdapter->dwRxDescIdx);
1143 }
1144 else
1145 {
1146 TRC("RX buffer empty %d\n", pAdapter->dwRxDescIdx);
1147 }
1149 dwRetVal = EC_E_NOERROR;
1151 Exit:
1153 return dwRetVal;
1154 }
1156 /********************************************************************************/
1157 /** \brief Release a frame buffer from DMA memory
1158 *
1159 * \return EC_E_NOERROR or error code.
1160 */
1161 static void FreeRecvFrameFromDma(
1162 PT_CPSW_INTERNAL pAdapter,
1163 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
1164 )
1165 {
1166 EC_UNREFPARM(pAdapter);
1168 T_CPSW_BUFENTRY* pBufEntry = (T_CPSW_BUFENTRY *)(pLinkFrameDesc->pbyFrame - CPSW_BUFENTRY_FRAME_OFFSET);
1169 #if defined DEBUG
1170 EC_T_BYTE* pBufMem = (EC_T_BYTE *)pBufEntry;
1171 LinkOsDbgAssert((EC_T_DWORD)pBufMem == CPSW_CACHE_DOWN((EC_T_DWORD)pBufMem));
1172 LinkOsDbgAssert(pBufEntry->dwMagicKey == BUFFER_MAGIC_RX);
1174 // Check if frame address was allocated from the buffer pool
1175 #if defined COPY_FRAME
1176 LinkOsDbgAssert((pBufMem >= pAdapter->pRxCachedBuffer)
1177 && ((pBufMem + pLinkFrameDesc->dwSize) <= (pAdapter->pRxCachedBuffer + pAdapter->dwRxCachedBufferSize)));
1178 #else
1179 LinkOsDbgAssert((pBufMem >= pAdapter->pRxBuffer)
1180 && ((pBufMem + pLinkFrameDesc->dwSize) <= (pAdapter->pRxBuffer + pAdapter->dwRxBufferSize)));
1181 #endif
1182 #endif /* DEBUG */
1184 CPSWFreeBuffer(pBufEntry);
1185 }
1187 /********************************************************************************/
1188 /** \brief Poll for received frame. This function is called by the ethercat Master
1189 * if the function EcLinkGetMode() returns EcLinkMode_POLLING
1190 *
1191 * \return EC_E_NOERROR or error code.
1192 */
1193 static EC_T_DWORD EcLinkRecvFrame(
1194 void* pvInstance,
1195 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
1196 )
1197 {
1198 EC_T_DWORD dwRetVal = EC_E_ERROR;
1199 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL)pvInstance;
1201 #if defined DEBUG
1202 /* check for Type Signature */
1203 if (!IsCorrectAdapter(pAdapter) || EC_NULL == pLinkFrameDesc)
1204 {
1205 ERR("EcLinkRecvFrame: Invalid parameter");
1206 dwRetVal = EC_E_INVALIDPARM;
1207 goto Exit;
1208 }
1209 #endif
1211 // Needed by upper layer
1212 pLinkFrameDesc->pbyFrame = NULL;
1213 pLinkFrameDesc->dwSize = 0;
1215 dwRetVal = EcLinkRecvFrameFromDma(pAdapter, pLinkFrameDesc);
1216 if (EC_E_NOERROR != dwRetVal)
1217 {
1218 goto Exit;
1219 }
1221 // copy data from DMA buffer to rx buffer
1222 if (pAdapter->oInitParms.bNotUseDmaBuffers && pLinkFrameDesc->pbyFrame && pLinkFrameDesc->dwSize)
1223 {
1224 EC_T_BYTE* pbyFrame = EC_NULL;
1226 dwRetVal = pAdapter->rxBuffers.Alloc(&pbyFrame);
1227 if (EC_E_NOERROR != dwRetVal)
1228 {
1229 FreeRecvFrameFromDma(pAdapter, pLinkFrameDesc);
1230 pLinkFrameDesc->dwSize = 0;
1231 pLinkFrameDesc->pbyFrame = EC_NULL;
1232 goto Exit;
1233 }
1235 // copy data and return DMA buffer
1236 LinkOsMemcpy(pbyFrame, pLinkFrameDesc->pbyFrame, pLinkFrameDesc->dwSize);
1237 FreeRecvFrameFromDma(pAdapter, pLinkFrameDesc);
1239 pLinkFrameDesc->pbyFrame = pbyFrame;
1240 }
1242 dwRetVal = EC_E_NOERROR;
1244 Exit:
1246 return dwRetVal;
1247 }
1249 /********************************************************************************/
1250 /** \brief Allocate a frame buffer used for send
1251 *
1252 * If the link layer doesn't support frame allocation, this function must return
1253 * EC_E_NOTSUPPORTED
1254 *
1255 * \return EC_E_NOERROR or error code.
1256 */
1257 static EC_T_DWORD EcLinkAllocSendFrameFromDma(
1258 PT_CPSW_INTERNAL pAdapter,
1259 EC_T_LINK_FRAMEDESC* pLinkFrameDesc, /* [in/out] link frame descriptor */
1260 EC_T_DWORD dwSize /* [in] size of the frame to allocate */
1261 )
1262 {
1263 EC_T_DWORD dwRetVal = EC_E_ERROR;
1264 T_CPSW_FRAMEBUFENTRY* pBufEntry = EC_NULL;
1266 // Allocate TX buffer
1267 pBufEntry = CPSWAllocTxBuffer(pAdapter);
1268 if (pBufEntry == EC_NULL) // No free buffer found?
1269 {
1270 ERR("Can't alloc TX buffer (No free buffer)\n");
1271 dwRetVal = EC_E_NOMEMORY;
1272 goto Exit;
1273 }
1275 pBufEntry->bufentry.dwFrameLen = dwSize;
1277 pLinkFrameDesc->pbyFrame = pBufEntry->pFrame;
1278 pLinkFrameDesc->dwSize = dwSize;
1280 dwRetVal = EC_E_NOERROR;
1282 Exit:
1283 return dwRetVal;
1284 }
1286 /********************************************************************************/
1287 /** \brief Allocate a frame buffer used for send
1288 *
1289 * If the link layer doesn't support frame allocation, this function must return
1290 * EC_E_NOTSUPPORTED
1291 *
1292 * \return EC_E_NOERROR or error code.
1293 */
1294 static EC_T_DWORD EcLinkAllocSendFrame(
1295 void* pvInstance,
1296 EC_T_LINK_FRAMEDESC* pLinkFrameDesc, /* [in/out] link frame descriptor */
1297 EC_T_DWORD dwSize /* [in] size of the frame to allocate */
1298 )
1299 {
1300 EC_T_DWORD dwRetVal = EC_E_ERROR;
1301 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL)pvInstance;
1303 #if defined DEBUG
1304 if (!IsCorrectAdapter(pAdapter) || EC_NULL == pLinkFrameDesc)
1305 {
1306 ERR("Can't alloc TX buffer (Invalid param)\n");
1307 dwRetVal = EC_E_INVALIDPARM;
1308 goto Exit;
1309 }
1310 #endif
1312 // Needed by upper layer
1313 pLinkFrameDesc->pbyFrame = NULL;
1314 pLinkFrameDesc->dwSize = 0;
1316 // license check
1317 if (0x4154 == dwSize)
1318 {
1319 EC_T_BYTE* pDest;
1321 if (pLinkFrameDesc->pdwTimeStampLo)
1322 {
1323 pDest = (EC_T_BYTE*)pLinkFrameDesc->pdwTimeStampLo;
1324 *pDest++ = pAdapter->abyStationAddress[0];
1325 *pDest++ = pAdapter->abyStationAddress[1];
1326 *pDest++ = pAdapter->abyStationAddress[2];
1327 *pDest++ = pAdapter->abyStationAddress[3];
1328 }
1329 if (pLinkFrameDesc->pdwTimeStampPostLo)
1330 {
1331 pDest = (EC_T_BYTE*)pLinkFrameDesc->pdwTimeStampPostLo;
1332 *pDest++ = pAdapter->abyStationAddress[4];
1333 *pDest++ = pAdapter->abyStationAddress[5];
1334 *pDest++ = 0;
1335 *pDest++ = 0;
1336 }
1337 dwRetVal = EC_E_NOERROR;
1338 goto Exit;
1339 }
1341 if (pAdapter->oInitParms.bNotUseDmaBuffers)
1342 {
1343 dwRetVal = EC_E_NOTSUPPORTED;
1344 goto Exit;
1345 }
1347 dwRetVal = EcLinkAllocSendFrameFromDma(pAdapter, pLinkFrameDesc, dwSize);
1349 Exit:
1351 return dwRetVal;
1352 }
1354 /********************************************************************************/
1355 /** \brief Release a frame buffer previously allocated with EcLinkAllocFrame()
1356 *
1357 * \return EC_E_NOERROR or error code.
1358 */
1359 static void EcLinkFreeSendFrame(
1360 void* pvInstance,
1361 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
1362 )
1363 {
1364 EC_UNREFPARM(pvInstance);
1366 if (!pLinkFrameDesc || !pLinkFrameDesc->pbyFrame)
1367 {
1368 return; // wrong parameter
1369 }
1371 T_CPSW_BUFENTRY* pBufEntry = (T_CPSW_BUFENTRY *)(pLinkFrameDesc->pbyFrame - CPSW_BUFENTRY_FRAME_OFFSET);
1372 CPSWFreeBuffer(pBufEntry); // Free buffer from cached pool
1373 }
1375 /********************************************************************************/
1376 /** \brief Release a frame buffer given to the ethercat master through the receive
1377 * callback function
1378 *
1379 * \return EC_E_NOERROR or error code.
1380 */
1381 static void EcLinkFreeRecvFrame(
1382 void* pvInstance,
1383 EC_T_LINK_FRAMEDESC* pLinkFrameDesc /* [in] link frame descriptor */
1384 )
1385 {
1386 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL) pvInstance;
1388 #if defined DEBUG
1389 if (!IsCorrectAdapter(pAdapter) || pLinkFrameDesc == EC_NULL || pLinkFrameDesc->pbyFrame == EC_NULL)
1390 {
1391 return;
1392 }
1393 #endif
1395 if (pAdapter->oInitParms.bNotUseDmaBuffers)
1396 {
1397 pAdapter->rxBuffers.FreeBuffer(pLinkFrameDesc->pbyFrame);
1398 }
1399 else
1400 {
1401 FreeRecvFrameFromDma(pAdapter, pLinkFrameDesc);
1402 }
1403 }
1405 /********************************************************************************/
1406 /** \brief Determine link layer MAC address
1407 *
1408 * \return EC_E_NOERROR or error code.
1409 */
1410 static EC_T_DWORD EcLinkGetEthernetAddress(
1411 void* pvInstance,
1412 EC_T_BYTE* pbyEthernetAddress ) /* [out] Ethernet MAC address */
1413 {
1414 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL) pvInstance;
1415 EC_T_DWORD dwRetVal = EC_E_ERROR;
1417 if (!IsCorrectAdapter(pAdapter))
1418 {
1419 dwRetVal = EC_E_INVALIDPARM;
1420 goto Exit;
1421 }
1423 OsMemcpy(pbyEthernetAddress, pAdapter->abyStationAddress, MAC_ADDR_LEN);
1425 dwRetVal = EC_E_NOERROR;
1427 Exit:
1428 return dwRetVal;
1429 }
1431 /********************************************************************************/
1432 /** \brief Determine current link status.
1433 * This routine is called in the EtherCAT main cycle. Be fast...
1434 *
1435 * \return Current link status.
1436 */
1437 static EC_T_LINKSTATUS EcLinkGetStatus(void* pvInstance)
1438 {
1439 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL) pvInstance;
1441 #if defined DEBUG
1442 if (!IsCorrectAdapter(pAdapter))
1443 {
1444 return eLinkStatus_UNDEFINED;
1445 }
1446 #endif
1448 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_LINKOK)
1449 {
1450 if (pAdapter->dwLinkStatus &
1451 (CPSW_LINKFLAG_1000baseT_Half | CPSW_LINKFLAG_100baseT_Half | CPSW_LINKFLAG_10baseT_Half))
1452 {
1453 return eLinkStatus_HALFDUPLEX;
1454 }
1455 return eLinkStatus_OK;
1456 }
1457 return eLinkStatus_DISCONNECTED;
1458 }
1460 /********************************************************************************/
1461 /** \brief Determine link speed.
1462 *
1463 * \return link speed in MBit/sec
1464 */
1465 static EC_T_DWORD EcLinkGetSpeed(void* pvInstance)
1466 {
1467 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL) pvInstance;
1468 EC_T_DWORD dwSpeed = 10;
1470 #if defined DEBUG
1471 if (!IsCorrectAdapter(pAdapter))
1472 {
1473 dwSpeed = EC_E_INVALIDPARM;
1474 goto Exit;
1475 }
1476 #endif
1478 if (pAdapter->dwLinkStatus & (CPSW_LINKFLAG_1000baseT_Full | CPSW_LINKFLAG_1000baseT_Half))
1479 {
1480 dwSpeed = 1000;
1481 }
1482 else if (pAdapter->dwLinkStatus & (CPSW_LINKFLAG_100baseT_Full | CPSW_LINKFLAG_100baseT_Half))
1483 {
1484 dwSpeed = 100;
1485 }
1486 goto Exit;
1488 Exit:
1489 return dwSpeed;
1490 }
1492 /********************************************************************************/
1493 /** \brief Determine link mode
1494 *
1495 * \return link mode
1496 */
1497 static EC_T_LINKMODE EcLinkGetMode(void* pvInstance)
1498 {
1499 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL)pvInstance;
1500 EC_T_LINKMODE oLink = EcLinkMode_UNDEFINED;
1502 #if defined DEBUG
1503 if (!IsCorrectAdapter(pAdapter))
1504 {
1505 goto Exit;
1506 }
1507 #endif
1509 oLink = pAdapter->oInitParms.linkParms.eLinkMode;
1510 goto Exit;
1512 Exit:
1513 return oLink;
1514 }
1516 static EC_T_BOOL IsCorrectIoctlParamInput(EC_T_LINK_IOCTLPARMS* pParms, EC_T_DWORD dwSize)
1517 {
1518 if ((EC_NULL == pParms)
1519 || (EC_NULL == pParms->pbyInBuf)
1520 || (dwSize != pParms->dwInBufSize))
1521 return EC_FALSE;
1522 else
1523 return EC_TRUE;
1524 }
1526 static EC_T_BOOL IsCorrectIoctlParamOutput(EC_T_LINK_IOCTLPARMS* pParms, EC_T_DWORD dwSize)
1527 {
1528 if ((EC_NULL == pParms)
1529 || (EC_NULL == pParms->pbyOutBuf)
1530 || (dwSize != pParms->dwOutBufSize))
1531 return EC_FALSE;
1532 else
1533 return EC_TRUE;
1534 }
1536 /********************************************************************************/
1537 /** \brief Multi Purpose LinkLayer IOCTL
1538 *
1539 * \return EC_E_NOERROR or error code.
1540 */
1542 static EC_T_DWORD EcLinkIoctl(
1543 void* pvInstance,
1544 EC_T_DWORD dwCode,
1545 EC_T_LINK_IOCTLPARMS* pParms
1546 )
1547 {
1548 EC_T_DWORD dwRetVal = EC_E_ERROR;
1549 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL)pvInstance;
1551 #if defined DEBUG
1552 if (!IsCorrectAdapter(pAdapter))
1553 {
1554 dwRetVal = EC_E_INVALIDPARM;
1555 goto Exit;
1556 }
1557 #endif
1559 /* fan out IOCTL functions */
1561 switch( dwCode )
1562 {
1563 case EC_LINKIOCTL_REGISTER_FRAME_CLBK:
1564 {
1565 EC_T_LINK_FRM_RECV_CLBK* pFrameRecvClbk = EC_NULL;
1567 if (!IsCorrectIoctlParamInput(pParms, sizeof(EC_T_LINK_FRM_RECV_CLBK)))
1568 {
1569 dwRetVal = EC_E_INVALIDPARM;
1570 goto Exit;
1571 }
1573 pFrameRecvClbk = (EC_T_LINK_FRM_RECV_CLBK*)pParms->pbyInBuf;
1575 pAdapter->pvCallbackContext = pFrameRecvClbk->pvDevice;
1576 pAdapter->pfReceiveFrameCallback = (EC_T_RECEIVEFRAMECALLBACK)pFrameRecvClbk->pfFrameReceiveCallback;
1577 dwRetVal = EC_E_NOERROR;
1578 } break;
1579 case EC_LINKIOCTL_UNREGISTER_FRAME_CLBK:
1580 {
1581 pAdapter->pvCallbackContext = EC_NULL;
1582 pAdapter->pfReceiveFrameCallback = EC_NULL;
1583 dwRetVal = EC_E_NOERROR;
1584 } break;
1585 case EC_LINKIOCTL_INTERRUPTENABLE:
1586 {
1587 if (!IsCorrectIoctlParamInput(pParms, sizeof(EC_T_BOOL)))
1588 {
1589 dwRetVal = EC_E_INVALIDPARM;
1590 goto Exit;
1591 }
1593 if( EC_TRUE == ((EC_T_BOOL)(pParms->pbyInBuf)) )
1594 {
1595 LinkOsInterruptDisable( &(pAdapter->oIrqParms) );
1597 if( !LinkOsInterruptInitialize(&(pAdapter->oIrqParms)) )
1598 {
1599 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Cannot Initialize interrupt\n"));
1600 dwRetVal = EC_E_ERROR;
1601 goto Exit;
1602 }
1603 }
1604 else
1605 {
1606 LinkOsInterruptDisable( &(pAdapter->oIrqParms) );
1607 }
1608 } break;
1609 case EC_LINKIOCTL_PROMISCOUSMODE:
1610 {
1611 } break;
1612 case EC_LINKIOCTL_SETLINKMODE:
1613 {
1614 if (!IsCorrectIoctlParamInput(pParms, sizeof(EC_T_LINKSTATUS)))
1615 {
1616 dwRetVal = EC_E_INVALIDPARM;
1617 goto Exit;
1618 }
1620 switch( *((EC_T_LINKMODE*)pParms->pbyInBuf) )
1621 {
1622 case EcLinkMode_INTERRUPT:
1623 {
1624 if (EcLinkMode_INTERRUPT != pAdapter->oInitParms.linkParms.eLinkMode)
1625 {
1626 LinkOsInterruptDisable( &(pAdapter->oIrqParms) );
1628 if( !LinkOsInterruptInitialize(&(pAdapter->oIrqParms)) )
1629 {
1630 SYS_ERRORMSGC(("CPSW-EcLinkOpen(): Cannot Initialize interrupt\n"));
1631 dwRetVal = EC_E_ERROR;
1632 goto Exit;
1633 }
1634 }
1635 break;
1636 }
1637 case EcLinkMode_POLLING:
1638 {
1639 if (EcLinkMode_POLLING != pAdapter->oInitParms.linkParms.eLinkMode)
1640 {
1641 LinkOsInterruptDisable( &(pAdapter->oIrqParms) );
1642 }
1643 break;
1644 }
1645 default:
1646 {
1647 dwRetVal = EC_E_INVALIDPARM;
1648 goto Exit;
1649 }
1650 }
1652 pAdapter->oInitParms.linkParms.eLinkMode = *((EC_T_LINKMODE*)pParms->pbyInBuf);
1654 break;
1655 }
1656 case EC_LINKIOCTL_GETLINKMODE:
1657 {
1658 if (!IsCorrectIoctlParamOutput(pParms, sizeof(EC_T_LINKSTATUS)))
1659 {
1660 dwRetVal = EC_E_INVALIDPARM;
1661 goto Exit;
1662 }
1663 EC_T_LINKMODE *pMode = (EC_T_LINKMODE*)pParms->pbyOutBuf;
1664 *pMode = pAdapter->oInitParms.linkParms.eLinkMode;
1666 break;
1667 }
1668 case EC_LINKIOCTL_UPDATE_LINKSTATUS:
1669 {
1670 EC_T_DWORD dwOldLinkStatus = pAdapter->dwLinkStatus;
1671 pAdapter->dwLinkStatus = CPSWPhyUpdateLinkStatus(pAdapter);
1673 // Reconfigure MAC if PHY speed has changed
1674 if (dwOldLinkStatus != pAdapter->dwLinkStatus)
1675 {
1676 CPSWUpdateMacSpeed(pAdapter);
1677 }
1678 } break;
1679 case EC_LINKIOCTL_GET_ETHERNET_ADDRESS:
1680 {
1681 if (!IsCorrectIoctlParamOutput(pParms, 6))
1682 {
1683 dwRetVal = EC_E_INVALIDPARM;
1684 goto Exit;
1685 }
1687 dwRetVal = EcLinkGetEthernetAddress(pAdapter, pParms->pbyOutBuf);
1688 } break;
1689 case EC_LINKIOCTL_IS_FRAMETYPE_REQUIRED:
1690 {
1691 if (!IsCorrectIoctlParamOutput(pParms, sizeof(EC_T_BOOL)))
1692 {
1693 dwRetVal = EC_E_INVALIDPARM;
1694 goto Exit;
1695 }
1697 EC_T_BOOL* pbRequired = (EC_T_BOOL*)pParms->pbyOutBuf;
1698 *pbRequired = EC_TRUE;
1699 } break;
1700 case EC_LINKIOCTL_IS_FLUSHFRAMES_REQUIRED:
1701 {
1702 if (!IsCorrectIoctlParamOutput(pParms, sizeof(EC_T_BOOL)))
1703 {
1704 dwRetVal = EC_E_INVALIDPARM;
1705 goto Exit;
1706 }
1708 EC_T_BOOL* pbRequired = (EC_T_BOOL*)pParms->pbyOutBuf;
1709 *pbRequired = EC_TRUE;
1710 } break;
1711 case EC_LINKIOCTL_FLUSHFRAMES:
1712 {
1713 if (!pAdapter->bGatherFrames)
1714 {
1715 dwRetVal = EC_E_INVALIDSTATE;
1716 goto Exit;
1717 }
1719 /* send frames to DMA if we have something */
1720 if (pAdapter->pTxHeadDesc)
1721 {
1722 if (EC_E_NOERROR != (dwRetVal = CPSWWaitUntilTxDmaIsEmpty(pAdapter)))
1723 goto Exit;
1725 EC_T_DWORD txDescPa = dmadtor_va2pa(pAdapter, (EC_T_DWORD)pAdapter->pTxHeadDesc);
1726 W32(pAdapter->regs.StateRam->Tx_HDP[pAdapter->dwTxDmaChan], txDescPa);
1727 }
1728 pAdapter->bGatherFrames = EC_FALSE;
1729 pAdapter->pTxHeadDesc = EC_NULL;
1730 pAdapter->pTxTailDesc = EC_NULL;
1732 } break;
1733 case EC_LINKIOCTL_SENDCYCLICFRAMES:
1734 {
1735 /* cannot start sending if previous if not finished yet */
1736 if (pAdapter->bGatherFrames)
1737 {
1738 dwRetVal = EC_E_INVALIDSTATE;
1739 goto Exit;
1740 }
1741 pAdapter->bGatherFrames = EC_TRUE;
1742 pAdapter->dwTxDmaChan = pAdapter->dwTxDmaChanCyc;
1743 } break;
1744 case EC_LINKIOCTL_SENDACYCLICFRAMES:
1745 {
1746 /* cannot start sending if previous if not finished yet */
1747 if (pAdapter->bGatherFrames)
1748 {
1749 dwRetVal = EC_E_INVALIDSTATE;
1750 goto Exit;
1751 }
1752 pAdapter->bGatherFrames = EC_TRUE;
1753 pAdapter->dwTxDmaChan = pAdapter->dwTxDmaChanAcyc;
1754 } break;
1755 default:
1756 {
1757 dwRetVal = EC_E_INVALIDCMD;
1758 goto Exit;
1759 }
1760 }
1762 /* no error */
1764 dwRetVal = EC_E_NOERROR;
1766 Exit:
1767 if( EC_E_NOERROR != dwRetVal )
1768 {
1769 #if (defined __RCX__)
1770 if( bAllocIrq )
1771 {
1772 static RX_RESULT rxRes = RX_OK;
1773 rxRes = rX_MemFreeMemory(pAdapter->hInterrupt);
1774 OsDbgAssert(rxRes == RX_OK);
1775 }
1776 #else
1777 ;;
1778 #endif
1779 }
1780 return dwRetVal;
1781 }
1783 /********************************************************************************/
1784 /** \brief Register link layer driver.
1785 *
1786 * \return EC_E_NOERROR or error code.
1787 */
1788 CCALLING EC_T_DWORD emllRegisterCPSW(
1789 EC_T_LINK_DRV_DESC* pLinkDrvDesc /* [in,out] link layer driver descriptor */
1790 ,EC_T_DWORD dwLinkDrvDescSize /* [in] size in bytes of link layer driver descriptor */
1791 )
1792 {
1793 EC_T_DWORD dwResult = EC_E_NOERROR;
1794 EC_T_BOOL bInterfaceSupported = EC_FALSE;
1796 if (pLinkDrvDesc == EC_NULL)
1797 {
1798 ERR("emllRegister: NULL drive descriptor \n");
1799 dwResult = EC_E_INVALIDPARM;
1800 goto Exit;
1801 }
1803 if (pLinkDrvDesc->dwValidationPattern != LINK_LAYER_DRV_DESC_PATTERN)
1804 {
1805 ERR("emllRegister: invalid descriptor pattern 0x%x instead of 0x%x\n",
1806 pLinkDrvDesc->dwValidationPattern, LINK_LAYER_DRV_DESC_PATTERN);
1807 dwResult = EC_E_INVALIDPARM;
1808 goto Exit;
1809 }
1811 /* Check the size of the given link layer driver descriptor */
1812 if (dwLinkDrvDescSize > sizeof(EC_T_LINK_DRV_DESC))
1813 {
1814 ERR("emllRegister: link layer driver descriptor size too large\n");
1815 dwResult = EC_E_INVALIDPARM;
1816 goto Exit;
1817 }
1819 bInterfaceSupported = EC_FALSE;
1821 /* Check if the version of the interface is supported */
1822 if ( (sizeof(EC_T_LINK_DRV_DESC) == dwLinkDrvDescSize)
1823 && (pLinkDrvDesc->dwInterfaceVersion == LINK_LAYER_DRV_DESC_VERSION) )
1824 {
1825 bInterfaceSupported = EC_TRUE;
1826 }
1828 /* Interface is not supported. */
1829 if (! bInterfaceSupported)
1830 {
1831 ERR("emllRegister: invalid descriptor interface version 0x%x instead of 0x%x\n",
1832 pLinkDrvDesc->dwInterfaceVersion, LINK_LAYER_DRV_DESC_VERSION);
1833 dwResult = EC_E_INVALIDPARM;
1834 goto Exit;
1835 }
1837 pLinkDrvDesc->pfEcLinkOpen = EcLinkOpen;
1838 pLinkDrvDesc->pfEcLinkClose = EcLinkClose;
1839 pLinkDrvDesc->pfEcLinkSendFrame = EcLinkSendFrame;
1840 pLinkDrvDesc->pfEcLinkSendAndFreeFrame = EcLinkSendAndFreeFrame;
1841 pLinkDrvDesc->pfEcLinkRecvFrame = EcLinkRecvFrame;
1842 pLinkDrvDesc->pfEcLinkAllocSendFrame = EcLinkAllocSendFrame;
1843 pLinkDrvDesc->pfEcLinkFreeSendFrame = EcLinkFreeSendFrame;
1844 pLinkDrvDesc->pfEcLinkFreeRecvFrame = EcLinkFreeRecvFrame;
1845 pLinkDrvDesc->pfEcLinkGetEthernetAddress = EcLinkGetEthernetAddress;
1846 pLinkDrvDesc->pfEcLinkGetStatus = EcLinkGetStatus;
1847 pLinkDrvDesc->pfEcLinkGetSpeed = EcLinkGetSpeed;
1848 pLinkDrvDesc->pfEcLinkGetMode = EcLinkGetMode;
1849 pLinkDrvDesc->pfEcLinkIoctl = EcLinkIoctl;
1851 /* store DBG Message hook */
1852 LinkOsAddDbgMsgHook(pLinkDrvDesc->pfOsDbgMsgHook);
1854 Exit:
1856 return dwResult;
1857 }
1859 /***************************************************************************************************/
1860 /**
1861 \brief Acknowledge all pending NIC IRQ'S.
1863 \return EC_E_NOERROR on success, error code otherwise.
1864 */
1865 static EC_T_DWORD EcLinkIrqAck(void* pvContext)
1866 {
1867 EC_UNREFPARM(pvContext);
1868 return EC_E_NOERROR;
1869 }
1871 /***************************************************************************************************/
1872 /**
1873 \brief Mask NIC IRQ's.
1875 \return EC_E_NOERROR on success, error code otherwise.
1876 */
1877 static EC_T_DWORD EcLinkIrqClose(void* pvContext)
1878 {
1879 EC_UNREFPARM(pvContext);
1880 return EC_E_NOERROR;
1881 }
1883 /***************************************************************************************************/
1884 /**
1885 \brief Re-Open NIC IRQ's (UnMask).
1887 \return EC_E_NOERROR on success, error code otherwise.
1888 */
1889 static EC_T_DWORD EcLinkIrqOpen(void* pvContext)
1890 {
1891 EC_UNREFPARM(pvContext);
1892 return EC_E_NOERROR;
1893 }
1895 /***************************************************************************************************/
1896 /**
1897 \brief Handle Chip Interrupts.
1899 \return EC_E_NOERROR on success, error code otherwise.
1900 */
1901 static EC_T_DWORD DoHandleInterrupt(
1902 void * pvLinkParms
1903 )
1904 {
1905 EC_UNREFPARM(pvLinkParms);
1906 return EC_E_NOERROR;
1907 }
1910 /***************************************************************************************************
1911 * List Management
1912 */
1915 static EC_T_BOOL ListAddOI(PT_CPSW_INTERNAL poAdapter)
1916 {
1917 EC_T_BOOL bResult = EC_TRUE;
1918 PT_CPSW_INTERNAL oCur = EC_NULL;
1920 oCur = S_oOpenInstanceRoot;
1922 if( EC_NULL == oCur )
1923 {
1924 S_oOpenInstanceRoot = poAdapter;
1925 S_oOpenInstanceRoot->pPrev = S_oOpenInstanceRoot->pNext = EC_NULL;
1926 }
1927 else
1928 {
1929 while( EC_NULL != oCur->pNext )
1930 {
1931 oCur = oCur->pNext;
1932 }
1934 oCur->pNext = poAdapter;
1935 poAdapter->pPrev = oCur;
1936 poAdapter->pNext = EC_NULL;
1937 }
1939 return bResult;
1940 }
1942 static EC_T_BOOL ListRmOI(PT_CPSW_INTERNAL poAdapter)
1943 {
1944 EC_T_BOOL bResult = EC_TRUE;
1946 if( S_oOpenInstanceRoot == poAdapter )
1947 {
1948 S_oOpenInstanceRoot = poAdapter->pNext;
1949 }
1951 if( EC_NULL != poAdapter->pPrev )
1952 {
1953 poAdapter->pPrev->pNext = poAdapter->pNext;
1954 }
1956 if( EC_NULL != poAdapter->pNext )
1957 {
1958 poAdapter->pNext->pPrev = poAdapter->pPrev;
1959 }
1961 poAdapter->pPrev = EC_NULL;
1962 poAdapter->pNext = EC_NULL;
1964 return bResult;
1965 }
1967 static EC_T_BOOL ListCanAddAdapter(PT_CPSW_INTERNAL pAdapter)
1968 {
1969 PT_CPSW_INTERNAL oCur = EC_NULL;
1970 EC_T_BOOL bCanAddAdapter = EC_TRUE;
1972 oCur = S_oOpenInstanceRoot;
1974 while (EC_NULL != oCur)
1975 {
1976 /* port and DmaChan could not be identical */
1977 if ( (pAdapter->oInitParms.linkParms.dwInstance == oCur->oInitParms.linkParms.dwInstance)
1978 || (pAdapter->dwRxDmaChan == oCur->dwRxDmaChan))
1979 {
1980 bCanAddAdapter = EC_FALSE;
1981 break;
1982 }
1983 oCur = oCur->pNext;
1984 }
1986 return bCanAddAdapter;
1987 }
1990 /***************************************************************************************************
1991 * Helpers
1992 */
1995 static EC_T_DWORD CPSWMapMemory(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD dwBase, EC_T_DWORD *pdwBaseMapped)
1996 {
1997 EC_UNREFPARM(pAdapter);
1998 *pdwBaseMapped = (EC_T_DWORD)LinkOsMapMemory((EC_T_BYTE *)dwBase, CPSW_IO_LENGTH);
2000 if (*pdwBaseMapped == 0)
2001 {
2002 SYS_ERRORMSGC(("Error: CPSWMapMemory() LinkOsMapMemory can't mmap IO memory!\n"));
2003 return EC_E_NOMEMORY;
2004 }
2006 return EC_E_NOERROR;
2007 }
2009 static EC_T_BOOL CPSWSoftReset(volatile EC_T_DWORD *reg)
2010 {
2011 int timeout = 1000; // 10ms
2013 w32(reg, CPSW3G_SOFT_RESET_BIT);
2015 do
2016 {
2017 LinkOsSysDelay(10);
2018 }
2019 while (((r32(reg) & CPSW3G_SOFT_RESET_BIT) != 0) && timeout--);
2021 if ((r32(reg) & CPSW3G_SOFT_RESET_BIT) != 0)
2022 {
2023 return EC_FALSE;
2024 }
2025 return EC_TRUE;
2026 }
2028 static void CPSWReset(PT_CPSW_INTERNAL pAdapter)
2029 {
2030 PCPSW_REGSET pReg = &pAdapter->regs;
2032 // (5) Apply Soft Reset to 3PSW Subsystem, CPSW_3G, CPGMAC_SL 1/2 and CPDMA
2033 // \sa 9.2.1.13 Software Reset
2035 if (!CPSWSoftReset(&pReg->Dma->CPDMA_Soft_Reset))
2036 {
2037 ERR("Reset (CPDMA) failed.\n");
2038 return;
2039 }
2041 if (!CPSWSoftReset(&pReg->Cpsw->CPSW_Soft_Reset))
2042 {
2043 ERR("Reset (CPSW_3G) failed.\n");
2044 return;
2045 }
2047 if (!CPSWSoftReset(&pReg->Ss->Soft_Reset))
2048 {
2049 ERR("Reset (CPSW_3GSS) failed.\n");
2050 return;
2051 }
2053 // (6) Initialize the HDPs (Header Description Pointer) and CPs (Completion Pointer) to NULL
2054 for (int i = 0; i < CPDMA_MAX_CHANNELS; i++)
2055 {
2056 W32(pReg->StateRam->Tx_HDP[i], 0);
2057 W32(pReg->StateRam->Rx_HDP[i], 0);
2058 W32(pReg->StateRam->Tx_CP[i], 0);
2059 W32(pReg->StateRam->Rx_CP[i], 0);
2060 }
2061 }
2063 static void CPSWTeardown(PT_CPSW_INTERNAL pAdapter)
2064 {
2065 PCPSW_REGSET regs = &pAdapter->regs;
2066 int timeout = 500; // 5ms
2067 EC_T_BOOL bDmaEnabled = EC_FALSE;
2069 if (R32(regs->StateRam->Rx_HDP[pAdapter->dwRxDmaChan]) != 0)
2070 {
2071 bDmaEnabled = EC_TRUE;
2072 INF("Disable running RX-DMA\n");
2073 }
2075 if (R32(regs->StateRam->Tx_HDP[pAdapter->dwTxDmaChan]) != 0)
2076 {
2077 bDmaEnabled = EC_TRUE;
2078 INF("Disable running TX-DMA\n");
2079 }
2081 if (! bDmaEnabled) return;
2083 W32(regs->Dma->Rx_Teardown, pAdapter->dwRxDmaChan); // Shutdown RX DMA
2084 W32(regs->Dma->Tx_Teardown, pAdapter->dwTxDmaChan); // Shutdown TX DMA
2086 while ( R32(regs->StateRam->Rx_HDP[pAdapter->dwRxDmaChan]) != 0
2087 && R32(regs->StateRam->Tx_HDP[pAdapter->dwTxDmaChan]) != 0
2088 && timeout--)
2089 {
2090 LinkOsSysDelay(10);
2091 }
2093 if (timeout < 0)
2094 {
2095 ERR("DMA teardown timeout\n");
2096 return;
2097 }
2099 W32(regs->StateRam->Rx_CP[pAdapter->dwRxDmaChan], 0);
2100 W32(regs->StateRam->Tx_CP[pAdapter->dwTxDmaChan], 0);
2102 INF("RX+TX DMA disabled. Delay %d\n", timeout);
2103 }
2105 static inline void CPSWSetMacAddress(volatile CPSW_SLAVE_REGS* pSlaveReg, EC_T_BYTE macAddr[6])
2106 {
2107 W32(pSlaveReg->SL_SA_LO, (macAddr[5] << 8) | macAddr[4]);
2108 W32(pSlaveReg->SL_SA_HI, (macAddr[3] << 24) | (macAddr[2] << 16) |
2109 (macAddr[1] << 8) | macAddr[0]);
2110 }
2112 /***************************************************************************************************
2113 * MDIO
2114 */
2116 static void CPSWMdioInit(PT_CPSW_INTERNAL pAdapter)
2117 {
2118 volatile PCPSW_MDIO_REGS pMdio = pAdapter->regs.Mdio;
2120 DBG("MDIO Version 0x%08x\n", R32(pMdio->Version));
2122 if (pAdapter->oInitParms.bMaster)
2123 {
2124 // 1. Configure the PREAMBLE and CLKDIV bits in the MDIO Control register (CONTROL).
2125 // 2. Enable the MDIO module by setting the ENABLE bit in CONTROL.
2126 W32(pMdio->Control, MDIO_ENABLE | 0xFF);
2127 }
2129 // 3. The MDIO PHY alive status register (ALIVE) can be read in polling fashion until a PHY connected to
2130 // the system responded, and the MDIO PHY link status register (LINK) can determine whether this PHY
2131 // already has a link.
2132 // N/A
2134 // 4. Setup the appropriate PHY addresses in the MDIO user PHY select register (USERPHYSELn), and set
2135 // the LINKINTENB bit to enable a link change event interrupt if desirable.
2136 W32(pMdio->Useraccess[CPSWPortIdx(pAdapter)].physel, pAdapter->oInitParms.dwPhyAddr);
2138 // 5. If an interrupt on general MDIO register access is desired, set the corresponding bit in the MDIO user
2139 // command complete interrupt mask set register (USERINTMASKSET) to use the MDIO user access
2140 // register (USERACCESSn). Since only one PHY is used in this device, the application software can use
2141 // one USERACCESSn to trigger a completion interrupt; the other USERACCESSn is not setup.
2142 // N/A
2143 }
2146 static EC_T_BOOL MdioWaitForAccessComplete(volatile EC_T_DWORD *pAccess)
2147 {
2148 int timeout = 100;
2150 while ((r32(pAccess) & MDIO_GO) && timeout--)
2151 {
2152 LinkOsSysDelay(10);
2153 }
2155 if (timeout < 0)
2156 {
2157 ERR("mdio wait timeout\n");
2158 return EC_FALSE;
2159 }
2161 return EC_TRUE;
2162 }
2164 /* \brief MDIO read
2165 *
2166 * \param dwPhyAddr 5-bit PHY address
2167 * \param dwRegNo 5-bit PHY register field to read
2168 * \return Read PHY register value or MDIO_ERROR on error
2169 */
2170 static EC_T_DWORD CPSWMdioRead(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD dwRegNo)
2171 {
2172 EC_T_DWORD dwRet = MDIO_ERROR;
2173 volatile PCPSW_MDIO_REGS pMdio = pAdapter->regs.Mdio;
2174 EC_T_DWORD dwPortIdx = CPSWPortIdx(pAdapter);
2175 volatile PCPSW_MDIO_USR_REGS pMdioPort = &pMdio->Useraccess[dwPortIdx];
2176 EC_T_DWORD dwPhyAddr = pAdapter->oInitParms.dwPhyAddr & 0x1F;
2178 // 1. Check to ensure that the GO bit in the MDIO user access register (USERACCESSn) is cleared.
2179 if (!MdioWaitForAccessComplete(&pMdioPort->access)) goto Exit;
2181 // 2. Write to the GO, REGADR, and PHYADR bits in USERACCESSn corresponding to the PHY and PHY
2182 // register you want to read.
2183 W32(pMdioPort->access,
2184 MDIO_GO | MDIO_READ |
2185 ((dwRegNo & 0x1F) << 21) |
2186 ((dwPhyAddr & 0x1F) << 16));
2188 // 3. The read data value is available in the DATA bits in USERACCESSn after the module completes the
2189 // read operation on the serial bus. Completion of the read operation can be determined by polling the
2190 // GO and ACK bits in USERACCESSn. After the GO bit has cleared, the ACK bit is set on a successful
2191 // read.
2192 if (! MdioWaitForAccessComplete(&pMdioPort->access)) goto Exit;
2193 if (! (R32(pMdioPort->access) & MDIO_ACK))
2194 {
2195 ERR("mdio ACK missing\n");
2196 goto Exit;
2197 }
2199 dwRet = R32(pMdioPort->access) & 0xFFFF;
2201 // 4. Completion of the operation sets the corresponding USERINTRAW bit (0 or 1) in the MDIO user
2202 // command complete interrupt register (USERINTRAW) corresponding to USERACCESSn used. If
2203 // interrupts have been enabled on this bit using the MDIO user command complete interrupt mask set
2204 // register (USERINTMASKSET), then the bit is also set in the MDIO user command complete interrupt
2205 // register (USERINTMASKED) and an interrupt is triggered on the CPU.
2206 // N/A
2208 Exit:
2210 if (dwRet == MDIO_ERROR)
2211 {
2212 INF("mdio reg %d read error\n", dwRegNo);
2213 }
2215 return dwRet;
2216 }
2218 /* \brief MDIO write
2219 *
2220 * \param dwPhyAddr 5-bit PHY address
2221 * \param dwRegNo 5-bit PHY register field to write
2222 * \param dwValue Value to write to the PHY register
2223 * \return EC_TRUE on success or EC_FALSE on error
2224 */
2225 static EC_T_BOOL CPSWMdioWrite(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD dwRegNo, EC_T_DWORD dwValue)
2226 {
2227 EC_T_BOOL bRet = EC_FALSE;
2228 volatile PCPSW_MDIO_REGS pMdio = pAdapter->regs.Mdio;
2229 EC_T_DWORD dwPortIdx = CPSWPortIdx(pAdapter);
2230 volatile PCPSW_MDIO_USR_REGS pMdioPort = &pMdio->Useraccess[dwPortIdx];
2231 EC_T_DWORD dwPhyAddr = pAdapter->oInitParms.dwPhyAddr & 0x1F;
2233 // 1. Check to ensure that the GO bit in the MDIO user access register (USERACCESSn) is cleared.
2234 if (!MdioWaitForAccessComplete(&pMdioPort->access)) goto Exit;
2236 // 2. Write to the GO, WRITE, REGADR, PHYADR, and DATA bits in USERACCESSn corresponding to the
2237 // PHY and PHY register you want to write.
2238 W32(pMdioPort->access,
2239 MDIO_GO | MDIO_WRITE |
2240 ((dwRegNo & 0x1F) << 21) |
2241 ((dwPhyAddr & 0x1F) << 16) |
2242 (dwValue & 0xFFFF));
2244 // 3. The write operation to the PHY is scheduled and completed by the MDIO module. Completion of the
2245 // write operation can be determined by polling the GO bit in USERACCESS n for a 0.
2246 if (! MdioWaitForAccessComplete(&pMdioPort->access)) goto Exit;
2248 bRet = EC_TRUE;
2250 Exit:
2251 return bRet;
2252 }
2254 /***************************************************************************************************
2255 * PHY & Co
2256 */
2258 static EC_T_BOOL CPSWPhySetup(PT_CPSW_INTERNAL pAdapter)
2259 {
2260 EC_T_BOOL bRet = EC_FALSE;
2261 EC_T_DWORD tmp;
2262 EC_T_DWORD dwPhyId = 0;
2263 int sleepTick = 50; // ms
2264 int timeout = 6000 / sleepTick; // 6s
2266 if ((tmp = CPSWMdioRead(pAdapter, MII_PHYID1)) == MDIO_ERROR) goto Exit;
2267 dwPhyId = tmp;
2268 if ((tmp = CPSWMdioRead(pAdapter, MII_PHYID2)) == MDIO_ERROR) goto Exit;
2269 dwPhyId = (dwPhyId << 16) | tmp;
2271 if ((dwPhyId == 0xFFFFFFFF) || (dwPhyId == 0))
2272 {
2273 ERR("No PHY found at MII addr %d\n", pAdapter->oInitParms.dwPhyAddr);
2274 goto Exit;
2275 }
2277 INF("PHY found. Id=0x%08x\n", dwPhyId);
2279 if (!CPSWPhyQueryCapabilities(pAdapter))
2280 {
2281 ERR("Query PHY capabilities failed\n");
2282 goto Exit;
2283 }
2285 if (pAdapter->oInitParms.bPhyRestartAutoNegotiation)
2286 {
2287 INF("Restart PHY auto negotiation\n");
2289 // Restart auto negotiation
2290 if ((tmp = CPSWMdioRead(pAdapter, MII_CR)) == MDIO_ERROR) goto Exit;
2291 tmp |= MII_CR_ANRESTART | MII_CR_ANENABLE;
2292 tmp &= ~0x0800;
2293 if (!CPSWMdioWrite(pAdapter, MII_CR, tmp)) goto Exit;
2295 // Poll for auto negotiation completion
2296 // Read TBI SR to ensure SR[AN Done]=1 and SR[Link Status]=1.
2297 do
2298 {
2299 if ((tmp = CPSWMdioRead(pAdapter, MII_SR)) == MDIO_ERROR) goto Exit;
2300 LinkOsSleep(sleepTick);
2301 } while ( ((tmp & MII_SR_LINKOKVAL) != MII_SR_LINKOKVAL) && timeout-- );
2303 if (timeout < 0)
2304 {
2305 // No error. Ethernet cable may not be connected.
2306 INF("PHY link timeout (waiting for auto negotiation completion).\n");
2307 bRet = EC_TRUE;
2308 goto Exit;
2309 }
2311 if (ATH8031_PHY_ID == dwPhyId && eCpswPhySource_RGMII == pAdapter->oInitParms.ePhyConnection)
2312 {
2313 /* special initialization for ATH8031 PHY required */
2314 CPSWMdioWrite(pAdapter, AT803X_DEBUG_ADDR, 0x00000005);
2315 CPSWMdioWrite(pAdapter, AT803X_DEBUG_DATA, 0x00000100);
2316 }
2318 INF("PHY auto negotiation completed\n");
2319 }
2321 bRet = EC_TRUE;
2323 Exit:
2324 return bRet;
2325 }
2327 static EC_T_DWORD CPSWPhyUpdateLinkStatus(PT_CPSW_INTERNAL pAdapter)
2328 {
2329 EC_T_DWORD dwStat = 0;
2330 EC_T_DWORD dwLpa1000 = 0;
2331 EC_T_DWORD dwAdv1000 = 0;
2332 EC_T_DWORD dwLpa = 0;
2333 EC_T_DWORD dwAdv = 0;
2334 EC_T_DWORD dwLinkStatus = 0;
2336 if ((dwStat = CPSWMdioRead(pAdapter, MII_SR)) == MDIO_ERROR) goto Exit;
2337 if (dwStat & MII_SR_LSTATUS)
2338 {
2339 dwLinkStatus |= CPSW_LINKFLAG_LINKOK;
2340 }
2342 if (pAdapter->dwPhyFeatures & (CPSW_LINKFLAG_1000baseT_Half | CPSW_LINKFLAG_1000baseT_Full))
2343 {
2344 // Link partner ability (advertised by remote PHY)
2345 if ((dwLpa1000 = CPSWMdioRead(pAdapter, MII_STAT1000)) == MDIO_ERROR) goto Exit;
2347 // Local ability (advertised by local PHY)
2348 if ((dwAdv1000 = CPSWMdioRead(pAdapter, MII_CTRL1000)) == MDIO_ERROR) goto Exit;
2350 // If local and remote abilities match, then this is the current line speed.
2351 dwLpa1000 &= dwAdv1000 << 2;
2352 }
2354 // Link partner ability (advertised by remote PHY)
2355 if ((dwLpa = CPSWMdioRead(pAdapter, MII_ANLPBPA)) == MDIO_ERROR) goto Exit;
2357 // Local ability (advertised by local PHY)
2358 if ((dwAdv = CPSWMdioRead(pAdapter, MII_ANA)) == MDIO_ERROR) goto Exit;
2360 // If local and remote abilities match, then this is the current line speed.
2361 dwLpa &= dwAdv;
2363 if (dwLpa1000 & MII_STAT1000_1000FDX)
2364 {
2365 dwLinkStatus |= CPSW_LINKFLAG_1000baseT_Full;
2366 }
2367 else if (dwLpa1000 & MII_STAT1000_1000HDX)
2368 {
2369 dwLinkStatus |= CPSW_LINKFLAG_1000baseT_Half;
2370 }
2371 else if (dwLpa & MII_ANLPBPA_100FDX)
2372 {
2373 dwLinkStatus |= CPSW_LINKFLAG_100baseT_Full;
2374 }
2375 else if (dwLpa & MII_ANLPBPA_100HDX)
2376 {
2377 dwLinkStatus |= CPSW_LINKFLAG_100baseT_Half;
2378 }
2379 else if (dwLpa & MII_ANLPBPA_10FDX)
2380 {
2381 dwLinkStatus |= CPSW_LINKFLAG_10baseT_Full;
2382 }
2383 else
2384 {
2385 dwLinkStatus |= CPSW_LINKFLAG_10baseT_Half;
2386 }
2388 Exit:
2389 return dwLinkStatus;
2390 }
2392 static EC_T_BOOL CPSWPhyQueryCapabilities(PT_CPSW_INTERNAL pAdapter)
2393 {
2394 EC_T_BOOL bRet = EC_FALSE;
2395 EC_T_DWORD dwStat;
2396 EC_T_DWORD dwEstat;
2398 pAdapter->dwPhyFeatures = 0;
2400 // Query if register 15 (Extended Status is available)
2401 if ((dwStat = CPSWMdioRead(pAdapter, MII_SR)) == MDIO_ERROR) goto Exit;
2402 if (dwStat & MII_SR_ESTATEN)
2403 {
2404 if ((dwEstat = CPSWMdioRead(pAdapter, MII_ESTATUS)) == MDIO_ERROR) goto Exit;
2406 if (dwEstat & MII_ESTATUS_1000HDX)
2407 {
2408 pAdapter->dwPhyFeatures |= CPSW_LINKFLAG_1000baseT_Half;
2409 }
2410 if (dwEstat & MII_ESTATUS_1000FDX)
2411 {
2412 pAdapter->dwPhyFeatures |= CPSW_LINKFLAG_1000baseT_Full;
2413 }
2414 }
2415 if (dwStat & MII_SR_100HALF)
2416 {
2417 pAdapter->dwPhyFeatures |= CPSW_LINKFLAG_100baseT_Half;
2418 }
2419 if (dwStat & MII_SR_100FULL)
2420 {
2421 pAdapter->dwPhyFeatures |= CPSW_LINKFLAG_100baseT_Full;
2422 }
2423 if (dwStat & MII_SR_10HALF)
2424 {
2425 pAdapter->dwPhyFeatures |= CPSW_LINKFLAG_10baseT_Half;
2426 }
2427 if (dwStat & MII_SR_10FULL)
2428 {
2429 pAdapter->dwPhyFeatures |= CPSW_LINKFLAG_10baseT_Full;
2430 }
2432 bRet = EC_TRUE;
2434 Exit:
2435 return bRet;
2436 }
2438 //
2439 // Configure MAC for P1 or P2
2440 //
2441 static void CPSWSetupSliver(PT_CPSW_INTERNAL pAdapter)
2442 {
2443 PCPSW_REGSET regs = &pAdapter->regs;
2444 volatile PCPSW_SLIVER_REGS pSliverReg = regs->SelectedSliver;
2445 EC_T_DWORD dwPortIdx = CPSWPortIdx(pAdapter);
2447 if (!CPSWPhySetup(pAdapter))
2448 {
2449 ERR("PHY initialization failed\n");
2450 goto Exit;
2451 }
2452 pAdapter->dwLinkStatus = CPSWPhyUpdateLinkStatus(pAdapter);
2454 #ifdef DEBUG
2455 DBG(CPSWID "Link status: ");
2456 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_LINKOK) PRINT("LINK-UP ");
2457 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_1000baseT_Full) PRINT("1000-FD ");
2458 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_1000baseT_Half) PRINT("1000-HD ");
2459 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_100baseT_Full) PRINT("100-FD ");
2460 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_100baseT_Half) PRINT("100-HD ");
2461 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_10baseT_Full) PRINT("10-FD ");
2462 if (pAdapter->dwLinkStatus & CPSW_LINKFLAG_10baseT_Half) PRINT("10-HD ");
2463 PRINT("\n");
2464 #endif
2466 // (15) Configure CPGMAC_SL1 and CPGMAC_SL2, as per the desired mode of operations.
2468 if (!CPSWSoftReset(&pSliverReg->SL_Soft_Reset))
2469 {
2470 ERR("Reset (CPGMAC_SL%d) failed.\n", dwPortIdx);
2471 goto Exit;
2472 }
2474 // RX Packet Priority to Header Priority Mapping
2475 W32(pSliverReg->SL_Rx_Pri_Map, 0x76543210);
2477 W32(pSliverReg->SL_MacControl, 0);
2478 CPSWUpdateMacSpeed(pAdapter);
2480 Exit:
2481 return;
2482 }
2484 // \sa CE driver's Cpsw3g_cpgmac_control()
2485 static void CPSWUpdateMacSpeed(PT_CPSW_INTERNAL pAdapter)
2486 {
2487 volatile PCPSW_SLIVER_REGS pSliverReg = pAdapter->regs.SelectedSliver;
2488 EC_T_DWORD dwLinkStatus = pAdapter->dwLinkStatus;
2490 EC_T_DWORD dwMacCtrl = R32(pSliverReg->SL_MacControl);
2492 dwMacCtrl &= ~CPMAC_MACCONTROL_FULLDUPLEXEN_MASK;
2493 if (dwLinkStatus & (CPSW_LINKFLAG_1000baseT_Full | CPSW_LINKFLAG_100baseT_Full | CPSW_LINKFLAG_10baseT_Full))
2494 {
2495 dwMacCtrl |= CPMAC_MACCONTROL_FULLDUPLEXEN_MASK;
2496 }
2498 dwMacCtrl &= ~(CPMAC_MACCONTROL_GIGABITEN_MASK);
2499 if (dwLinkStatus & (CPSW_LINKFLAG_1000baseT_Full | CPSW_LINKFLAG_1000baseT_Half))
2500 {
2501 dwMacCtrl |= CPMAC_MACCONTROL_GIGABITEN_MASK;
2502 }
2504 dwMacCtrl &= ~(CPMAC_MACCONTROL_MIIEN_MASK);
2505 if (dwLinkStatus & (CPSW_LINKFLAG_100baseT_Full | CPSW_LINKFLAG_100baseT_Half))
2506 {
2507 dwMacCtrl |= CPMAC_MACCONTROL_MIIEN_MASK;
2509 if ( eCpswPhySource_RGMII == pAdapter->oInitParms.ePhyConnection )
2510 {
2511 // for RGMII set those bits to indicate that speed is 100Mbps
2512 dwMacCtrl |= CPMAC_MACCONTROL_IFCTLB_MASK | CPMAC_MACCONTROL_IFCTLA_MASK;
2513 }
2514 }
2516 W32(pSliverReg->SL_MacControl, dwMacCtrl);
2517 }
2519 /***************************************************************************************************
2520 * ALE (Address Lookup Engine)
2521 */
2523 #if !defined ALE_BYPASS
2524 static void CPSWAleTableEntrySet(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD tableIdx, EC_T_DWORD *pAleTableEntry)
2525 {
2526 volatile PCPSW_ALE_REGS pReg = pAdapter->regs.Ale;
2528 for (int i = 0; i < ALE_ENTRY_WORDS; i++)
2529 {
2530 W32(pReg->ALE_Tbl[i], pAleTableEntry[ALE_ENTRY_WORDS - i - 1]);
2531 }
2532 W32(pReg->ALE_TblCtl, tableIdx | ALE_PORTCTL_TABLEWRITE);
2533 }
2535 void CPSWAleTableEntryGet(PT_CPSW_INTERNAL pAdapter, EC_T_DWORD tableIdx, EC_T_DWORD *pAleTableEntry)
2536 {
2537 volatile PCPSW_ALE_REGS pReg = pAdapter->regs.Ale;
2539 W32(pReg->ALE_TblCtl, tableIdx);
2541 for (int i = 0; i < ALE_ENTRY_WORDS; i++)
2542 {
2543 pAleTableEntry[i] = R32(pReg->ALE_Tbl[ALE_ENTRY_WORDS - i - 1]);
2544 }
2545 }
2547 static void CPSWAleVlanEntrySet(
2548 PT_CPSW_INTERNAL pAdapter,
2549 EC_T_DWORD tableIdx,
2550 EC_T_DWORD vlanId,
2551 EC_T_DWORD portMask) // 0x1 | 0x2 | 0x4
2552 {
2553 EC_T_DWORD ale_v_entry[ALE_ENTRY_NUM_WORDS];
2554 EC_T_BYTE *pAle = (EC_T_BYTE *) ale_v_entry;
2555 memset(ale_v_entry, 0, sizeof(ale_v_entry));
2557 vlanId &= 0xFFF; // 12bit
2558 portMask &= 0x7; // 3 bit
2560 // Set up the VLAN Entry
2561 pAle[ALE_VLAN_ENTRY_MEMBER_LIST] = (EC_T_BYTE) portMask;
2562 pAle[ALE_VLAN_ENTRY_FRC_UNTAG_EGR] = (EC_T_BYTE) portMask;
2563 pAle[ALE_VLAN_ENTRY_ID_BIT0_BIT7] = (EC_T_BYTE) (vlanId & 0xFF);
2564 pAle[ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11] = (EC_T_BYTE) (ALE_ENTRY_VLAN | (vlanId >> 8));
2566 // Set the VLAN entry in the ALE table
2567 CPSWAleTableEntrySet(pAdapter, tableIdx, ale_v_entry);
2568 }
2570 static void CPSWAleVlanUcastEntrySet(
2571 PT_CPSW_INTERNAL pAdapter,
2572 EC_T_DWORD tableIdx,
2573 EC_T_DWORD portNo, // 0, 1, 2
2574 EC_T_DWORD vlanId,
2575 EC_T_BYTE ethAddress[MAC_ADDR_LEN])
2576 {
2577 EC_T_DWORD ale_vu_entry[ALE_ENTRY_NUM_WORDS];
2578 EC_T_BYTE *pAle = (EC_T_BYTE *) ale_vu_entry;
2579 memset(ale_vu_entry, 0, sizeof(ale_vu_entry));
2581 vlanId &= 0xFFF; // 12bit
2582 portNo &= 0x3; // 0, 1, 2
2584 for (int i = 0; i < MAC_ADDR_LEN; i++)
2585 {
2586 pAle[i] = ethAddress[MAC_ADDR_LEN - i - 1];
2587 }
2589 pAle[ALE_VLANUCAST_ENTRY_ID_BIT0_BIT7] = (EC_T_BYTE) (vlanId & 0xFF);
2590 pAle[ALE_VLANUCAST_ENTRY_TYPE_ID_BIT8_BIT11] = (EC_T_BYTE)
2591 (ALE_ENTRY_VLANUCAST | (vlanId >> 8));
2592 pAle[ALE_VLANUCAST_ENTRY_TYPE_PORTNO] = (EC_T_BYTE)
2593 (portNo << ALE_VLANUCAST_ENTRY_PORT_SHIFT);
2595 // Set the VLAN entry in the ALE table
2596 CPSWAleTableEntrySet(pAdapter, tableIdx, ale_vu_entry);
2597 }
2599 static void CPSWAleSetupTable(PT_CPSW_INTERNAL pAdapter)
2600 {
2601 EC_T_BOOL bMaster = pAdapter->oInitParms.bMaster;
2602 EC_T_DWORD dwOffs = bMaster ? 0 : 2;
2603 EC_T_DWORD dwPortIdx = CPSWPortIdx(pAdapter); // 0 .. 1
2604 EC_T_DWORD dwVlanId = dwPortIdx + 1; // Use portnumber (1 or 2) as VLAN Id
2606 // Idx0: Add a VLAN Table Entry with ports 0 and 1 as members (clear the flood masks).
2607 CPSWAleVlanEntrySet(pAdapter, 0 + dwOffs, dwVlanId, HOST_PORT_MASK | (1 << (dwPortIdx + 1)));
2609 // Idx1: Add a VLAN/Unicast Address Table Entry with the Port1/0 VLAN and a port number of 0.
2610 CPSWAleVlanUcastEntrySet(pAdapter, 1 + dwOffs, HOST_PORT_NO, dwVlanId, pAdapter->abyStationAddress);
2611 }
2612 #endif // if !defined ALE_BYPASS
2614 /***************************************************************************************************
2615 * DMA / Buffer
2616 */
2618 static void CPSWSetupBuffers(PT_CPSW_INTERNAL pAdapter)
2619 {
2620 T_CPSW_FRAMEBUFENTRY *pBufEntry;
2621 int i;
2623 for (i = 0; i < CPSW_RXDMABUFCNT; ++i)
2624 {
2625 pBufEntry = RX_DMABUF_PTR(i);
2626 pBufEntry->bufentry.dwMagicKey = BUFFER_MAGIC_RX;
2627 pBufEntry->bufentry.eBufState = BS_FREE;
2628 }
2630 for (i = 0; i < CPSW_TXDMABUFCNT; ++i)
2631 {
2632 pBufEntry = TX_DMABUF_PTR(i);
2633 pBufEntry->bufentry.dwMagicKey = BUFFER_MAGIC_TX;
2634 pBufEntry->bufentry.eBufState = BS_FREE;
2635 }
2637 #if defined COPY_FRAME
2638 for (i = 0; i < CPSW_RXCACHEDBUFCNT; ++i)
2639 {
2640 pBufEntry = RX_CACHEDBUF_PTR(i);
2641 pBufEntry->bufentry.dwMagicKey = BUFFER_MAGIC_RX;
2642 pBufEntry->bufentry.eBufState = BS_FREE;
2643 }
2645 for (i = 0; i < CPSW_TXCACHEDBUFCNT; ++i)
2646 {
2647 pBufEntry = TX_CACHEDBUF_PTR(i);
2648 pBufEntry->bufentry.dwMagicKey = BUFFER_MAGIC_TX;
2649 pBufEntry->bufentry.eBufState = BS_FREE;
2650 }
2651 #endif
2652 }
2654 //
2655 // Setup and link RX DMA descriptors
2656 //
2657 static void CPSWSetupRxDtors(PT_CPSW_INTERNAL pAdapter)
2658 {
2659 volatile T_CPSW_DESC *pRxDesc;
2660 T_CPSW_FRAMEBUFENTRY *pBufEntry;
2661 int i;
2663 #if !defined COPY_FRAME
2664 // Only half of the buffers are directly assigned here. The unused buffers are used in EcLinkReceiveFrame()
2665 // for descriptor assignment after DMA transfer has completed.
2666 pAdapter->dwRxBufIdx = CPSW_RXDESCNT;
2667 #endif
2669 for (i = 0; i < CPSW_RXDESCNT; ++i)
2670 {
2671 pRxDesc = RX_DESC_PTR(i);
2672 pBufEntry = RX_DMABUF_PTR(i);
2674 // Write cachelines back to memory
2675 LinkOsCacheDataSync(pBufEntry->pFrame,
2676 dma_va2pa(pAdapter, (EC_T_DWORD) pBufEntry->pFrame),
2677 CPSW_CACHE_UP(CPSW_RXBUFLEN - CACHELINE_SIZE));
2679 // Fill DMA dtor
2680 W32(pRxDesc->dwNext, dmadtor_va2pa(pAdapter, (EC_T_DWORD) RX_DESC_PTR(i + 1)));
2681 W32(pRxDesc->dwBuffer, dma_va2pa(pAdapter, (EC_T_DWORD) pBufEntry->pFrame));
2682 W32(pRxDesc->dwLen, CPDMA_RXBUFLEN);
2683 W32(pRxDesc->dwMode, CPDMA_DESC_OWNER | CPDMA_RXBUFLEN); // descriptor owned by MAC
2685 // Mark buffer as used
2686 pBufEntry->bufentry.eBufState = BS_ALLOC;
2687 }
2689 // Last dtor is EOQ
2690 pAdapter->pRxDesc[CPSW_RXDESCNT - 1].dwNext = 0;
2691 pAdapter->pRxTailDesc = RX_DESC_PTR(CPSW_RXDESCNT - 1);
2693 #if defined TRACE && 0
2694 for (i = 0; i < CPSW_RXDESCNT; ++i)
2695 {
2696 pRxDesc = &pAdapter->pRxDesc[i];
2697 TRC("pRxDescVirt 0x%08x, pRxDescPhys 0x%08x, Next 0x%08x, Buffer 0x%08x, Len 0x%08x, Mode 0x%08x\n",
2698 (EC_T_DWORD)pRxDesc,
2699 dmadtor_va2pa(pAdapter, (EC_T_DWORD) pRxDesc),
2700 R32(pRxDesc->dwNext),
2701 R32(pRxDesc->dwBuffer),
2702 R32(pRxDesc->dwLen),
2703 R32(pRxDesc->dwMode));
2704 }
2705 #endif
2706 }
2708 //
2709 // Setup and link TX DMA descriptors
2710 //
2711 static void CPSWSetupTxDtors(PT_CPSW_INTERNAL pAdapter)
2712 {
2713 #if defined COPY_FRAME
2714 volatile T_CPSW_DESC *pTxDesc;
2715 T_CPSW_FRAMEBUFENTRY *pBufEntry;
2716 int i;
2718 for (i = 0; i < CPSW_TXDESCNT; ++i) // Assign each TX-DMA dtor one fixed buffer
2719 {
2720 pTxDesc = TX_DESC_PTR(i);
2721 pBufEntry = TX_DMABUF_PTR(i);
2723 // Fill DMA dtor
2724 W32(pTxDesc->dwBuffer, dma_va2pa(pAdapter, (EC_T_DWORD) pBufEntry->pFrame));
2726 pBufEntry->bufentry.eBufState = BS_ALLOC;
2727 }
2728 #else
2729 EC_UNREFPARM(pAdapter);
2730 #endif
2731 }
2733 #if defined COPY_FRAME
2734 static T_CPSW_FRAMEBUFENTRY* CPSWFindNextFreeTxBufferCached(PT_CPSW_INTERNAL pAdapter)
2735 {
2736 T_CPSW_FRAMEBUFENTRY *pBufEntry = EC_NULL;
2738 // Search first free TX buffer
2739 for (int i = 0; i < CPSW_TXCACHEDBUFCNT; ++i)
2740 {
2741 pBufEntry = TX_CACHEDBUF_PTR(pAdapter->dwTxBufIdx);
2743 // Increment ring buffer pointer
2744 pAdapter->dwTxBufIdx = NEXT_TX_CACHEDBUF_IDX(pAdapter->dwTxBufIdx);
2746 if (pBufEntry->bufentry.eBufState == BS_FREE) return pBufEntry;
2747 }
2749 return EC_NULL;
2750 }
2751 #else
2752 static T_CPSW_FRAMEBUFENTRY* CPSWFindNextFreeTxBuffer(PT_CPSW_INTERNAL pAdapter)
2753 {
2754 volatile T_CPSW_DESC* pDesc = EC_NULL;
2755 T_CPSW_FRAMEBUFENTRY* pBufEntry = EC_NULL;
2757 // Search first free TX buffer
2758 for (int i = 0; i < CPSW_TXDMABUFCNT; ++i)
2759 {
2760 pBufEntry = TX_DMABUF_PTR(pAdapter->dwTxBufIdx);
2762 LinkOsMemoryBarrier();
2764 pDesc = &pAdapter->pTxDesc[pBufEntry->bufentry.dwDescIdx];
2766 LinkOsMemoryBarrier();
2768 LinkOsDbgAssert(pBufEntry->bufentry.dwMagicKey == BUFFER_MAGIC_TX);
2770 // Increment ring buffer pointer
2771 pAdapter->dwTxBufIdx = NEXT_TX_DMABUF_IDX(pAdapter->dwTxBufIdx);
2773 if ( (pBufEntry->bufentry.eBufState == BS_FREE) // Buffer not allocated or ...
2774 || ((pBufEntry->bufentry.eBufState == BS_DMA_STARTED) // buffer allocated and DMA pending and ...
2775 && (! (R32(pDesc->dwMode) & CPDMA_DESC_OWNER) ) // OWN bit in coresponding dtor cleared
2776 ) // -> DMA transfer completed
2777 )
2778 {
2779 return pBufEntry;
2780 }
2781 }
2783 return EC_NULL;
2784 }
2785 #endif
2787 static T_CPSW_FRAMEBUFENTRY* CPSWAllocTxBuffer(PT_CPSW_INTERNAL pAdapter)
2788 {
2789 T_CPSW_FRAMEBUFENTRY *pBuf;
2790 #if defined COPY_FRAME
2791 pBuf = CPSWFindNextFreeTxBufferCached(pAdapter);
2792 #else
2793 pBuf = CPSWFindNextFreeTxBuffer(pAdapter);
2794 #endif
2795 if (pBuf != EC_NULL)
2796 {
2797 pBuf->bufentry.eBufState = BS_ALLOC;
2798 }
2799 return pBuf;
2800 }
2802 #if defined COPY_FRAME
2803 static T_CPSW_FRAMEBUFENTRY* CPSWFindNextFreeRxBufferCached(PT_CPSW_INTERNAL pAdapter)
2804 {
2805 T_CPSW_FRAMEBUFENTRY* pBufEntry = EC_NULL;
2807 // Search next free RX buffer which is used to reassign the descriptor
2808 for (int i = 0; i < CPSW_RXCACHEDBUFCNT; ++i)
2809 {
2810 pBufEntry = RX_CACHEDBUF_PTR(pAdapter->dwRxBufIdx);
2812 LinkOsDbgAssert(pBufEntry->bufentry.dwMagicKey == BUFFER_MAGIC_RX);
2814 // Increment ring buffer pointer
2815 pAdapter->dwRxBufIdx = NEXT_RX_CACHEDBUF_IDX(pAdapter->dwRxBufIdx);
2817 if (pBufEntry->bufentry.eBufState == BS_FREE)
2818 {
2819 return pBufEntry;
2820 }
2821 }
2823 return EC_NULL;
2824 }
2825 #else
2826 static T_CPSW_FRAMEBUFENTRY* CPSWFindNextFreeRxBuffer(PT_CPSW_INTERNAL pAdapter)
2827 {
2828 T_CPSW_FRAMEBUFENTRY* pBufEntry = EC_NULL;
2830 // Search next free RX buffer which is used to reassign the descriptor
2831 for (int i = 0; i < CPSW_RXDMABUFCNT; ++i)
2832 {
2833 pBufEntry = RX_DMABUF_PTR(pAdapter->dwRxBufIdx);
2835 LinkOsDbgAssert(pBufEntry->bufentry.dwMagicKey == BUFFER_MAGIC_RX);
2837 // Increment ring buffer pointer
2838 pAdapter->dwRxBufIdx = NEXT_RX_DMABUF_IDX(pAdapter->dwRxBufIdx);
2840 if (pBufEntry->bufentry.eBufState == BS_FREE)
2841 {
2842 return pBufEntry;
2843 }
2844 }
2846 return EC_NULL;
2847 }
2848 #endif
2850 static T_CPSW_FRAMEBUFENTRY* CPSWAllocRxBuffer(PT_CPSW_INTERNAL pAdapter)
2851 {
2852 T_CPSW_FRAMEBUFENTRY *pBuf;
2853 #if defined COPY_FRAME
2854 pBuf = CPSWFindNextFreeRxBufferCached(pAdapter);
2855 #else
2856 pBuf = CPSWFindNextFreeRxBuffer(pAdapter);
2857 #endif
2858 if (pBuf != EC_NULL)
2859 {
2860 pBuf->bufentry.eBufState = BS_ALLOC;
2861 }
2862 return pBuf;
2863 }
2865 /***************************************************************************************************
2866 * Init
2867 */
2869 static void CPSWInitializeHardware(PT_CPSW_INTERNAL pAdapter)
2870 {
2871 PCPSW_REGSET regs = &pAdapter->regs;
2872 volatile PCPSW_SLAVE_REGS pSlaveReg = regs->SelectedSlave;
2873 EC_T_BOOL bMaster = pAdapter->oInitParms.bMaster;
2874 EC_T_DWORD dwPortIdx = CPSWPortIdx(pAdapter);
2875 EC_T_DWORD dwPacketPrio = pAdapter->dwRxDmaChan; // DMA chan is 0 .. 7. So can be mapped to packet prio.
2877 DBG("Tx Version 0x%08x\n", R32(regs->Dma->Tx_Idver));
2878 DBG("Rx Version 0x%08x\n", R32(regs->Dma->Rx_Idver));
2880 if (bMaster)
2881 {
2882 // (8) Configure the CPSW_3G_CONTROL register
2883 W32(regs->Cpsw->CPSW_Control, 0);
2885 // (9) Configure the Statistic Port Enable register
2886 W32(regs->Cpsw->CPSW_Stat_Port_En, 0);
2888 // (10) Configure ALE
2890 // Dual Mac Mode: Set the ale_vlan_aware bit in the ALE_Control register.
2891 #ifdef ALE_BYPASS
2892 W32(regs->Ale->ALE_Control,
2893 CPSW3G_ALECONTROL_ENABLEALE | CPSW3G_ALECONTROL_CLEARTABLE | CPSW3G_ALECONTROL_VLANAWARE
2894 | CPSW3G_ALECONTROL_ALEBYPASS);
2895 #else
2896 W32(regs->Ale->ALE_Control,
2897 CPSW3G_ALECONTROL_ENABLEALE | CPSW3G_ALECONTROL_CLEARTABLE | CPSW3G_ALECONTROL_VLANAWARE);
2898 #endif
2900 // Set the ports (host, port1, port2) to FORWARD
2901 W32(regs->Ale->ALE_PortCtl[0], ALE_PORTCTL_PSTATE_FORWARD);
2902 W32(regs->Ale->ALE_PortCtl[1], ALE_PORTCTL_PSTATE_FORWARD);
2903 W32(regs->Ale->ALE_PortCtl[2], ALE_PORTCTL_PSTATE_FORWARD);
2905 // Dual Mac Mode: Configure port0 and port1 for one VLAN ID;
2906 // port0 and port2 for a different VLAN ID.
2907 // Use VLAN ID 0 for the host port.
2908 W32(regs->Host->P0_Port_VLAN, 0);
2910 // (12) Configure the CPDMA receive DMA controller
2911 // (13) Configure the CPDMA transmit DMA controller
2913 // The queue uses a fixed (channel 7 highest priority) priority
2914 // scheme to select the next channel for transmission
2915 W32(regs->Dma->DMAControl, CPDMA_DMACONTROL_TXPTYPE_MASK);
2917 W32(regs->Dma->Tx_Control, CPDMA_TXCONTROL_TXEN); // Enable TX-DMA
2918 W32(regs->Dma->Rx_Control, CPDMA_RXCONTROL_RXEN); // Enable RX-DMA
2920 // CPSW CPDMA RX (PORT 0 TX) SWITCH PRIORITY TO DMA CHANNEL
2921 // E.g.: All priorities of port2 -> DMA channel 1
2922 // All priorities of port1 -> DMA channel 0
2923 // -> 0x11110000
2924 EC_T_DWORD dwChP2 = (dwPortIdx == 1) ? pAdapter->dwRxDmaChan : DMACHAN_INVERSE(pAdapter->dwRxDmaChan);
2925 EC_T_DWORD dwChP1 = DMACHAN_INVERSE(dwChP2);
2926 EC_T_DWORD dwTmp = (dwChP1 << 0) | (dwChP1 << 4) | (dwChP1 << 8) | (dwChP1 << 12) |
2927 (dwChP2 << 16) | (dwChP2 << 20) | (dwChP2 << 24) | (dwChP2 << 28);
2928 TRC("CPDMA_Rx_Ch_Map 0x%08x\n", dwTmp);
2929 W32(regs->Host->CPDMA_Rx_Ch_Map, dwTmp);
2931 // CPSW PORT 0 TX HEADER PRI TO SWITCH PRI MAPPING REGISTER
2932 // Map TX packet header priorities of:
2933 // 7 and 6 to switch queue priority 3 (highest)
2934 // 5 and 4 to switch queue priority 3
2935 // 3 and 2 to switch queue priority 2
2936 // 1 and 0 to switch queue priority 2
2937 W32(regs->Host->P0_Tx_Pri_Map, 0x33332222);
2939 // Dual Mac Mode: Select the dual mac mode on the port 0 FIFO by setting tx_in_sel[1:0] = 01 in P0_Tx_In_Ctl.
2940 W32(regs->Host->P0_Tx_In_Ctl, 0x1 << CPSW3G_PORTTXFIFO_INSEL_SHIFT);
2941 }
2943 // Dual Mac Mode: Configure port0 and port1 for one VLAN ID;
2944 // port0 and port2 for a different VLAN ID. Here we choose the
2945 // port number (1 or 2) as VLAN ID.
2946 W32(pSlaveReg->Port_VLAN, (dwPacketPrio << CPSW3G_PORTVLAN_PRI_SHIFT) | (dwPortIdx + 1));
2948 #if !defined ALE_BYPASS
2949 // Fill ALE table
2950 CPSWAleSetupTable(pAdapter);
2951 #endif
2953 // Set MAC address for port
2954 CPSWSetMacAddress(pSlaveReg, pAdapter->abyStationAddress);
2956 // (11) Configure the MDIO
2957 CPSWMdioInit(pAdapter);
2959 // (15) Configure CPGMAC_SL1 and CPGMAC_SL2, as per the desired mode of operations.
2960 CPSWSetupSliver(pAdapter);
2962 // CPSW PORT n TX HEADER PRIORITY TO SWITCH PRI MAPPING REGISTER
2963 // Map TX packet header priorities of:
2964 // 7 and 6 to switch queue priority 3 (highest)
2965 // 5 and 4 to switch queue priority 3
2966 // 3 and 2 to switch queue priority 2
2967 // 1 and 0 to switch queue priority 2
2968 W32(pSlaveReg->Tx_Pri_Map, 0x33332222);
2970 // FIFO allocation for TX:14, RX:6. (TX+RX=20)
2971 // W32(pSlaveReg->Max_Blks, 0xE6);
2973 // (16) Start up RX and TX DMA (Write to HDP of RX and TX)
2975 W32(regs->StateRam->Rx_HDP[pAdapter->dwRxDmaChan],
2976 dmadtor_va2pa(pAdapter, (EC_T_DWORD) pAdapter->pRxDesc));
2977 }
2979 static void CPSWMapRegisterSet(PT_CPSW_INTERNAL pAdapter)
2980 {
2981 PCPSW_REGSET pRegs = &pAdapter->regs;
2982 EC_T_LINK_PLATFORMDATA_CPSW *pPCfg = &pAdapter->oInitParms.oPlatCfg;
2983 EC_T_DWORD dwPortIdx = CPSWPortIdx(pAdapter);
2984 EC_T_DWORD dwBase = pAdapter->dwRegisterBase;
2986 pRegs->Cpsw = (PCPSW_REGS) dwBase;
2987 pRegs->Host = (PCPSW_HOST_REGS) (dwBase + pPCfg->dwHostPortOffs);
2988 pRegs->Ale = (PCPSW_ALE_REGS) (dwBase + pPCfg->dwCpswAleOffs);
2989 pRegs->Dma = (PCPSW_CPDMA_REGS) (dwBase + pPCfg->dwCpswCpdmaOffs);
2990 pRegs->StateRam = (PCPSW_STATERAM_REGS) (dwBase + pPCfg->dwCpdmaStateramOffs);
2991 pRegs->Ss = (PCPSW_SS_REGS) (dwBase + pPCfg->dwCpswSsOffs);
2992 pRegs->Mdio = (PCPSW_MDIO_REGS) (dwBase + pPCfg->dwMdioOffs);
2993 #ifdef USE_CPPI_RAM
2994 pRegs->BdRam = (T_CPSW_DESC *) (dwBase + pPCfg->dwBdRamOffs);
2995 #endif
2997 // Port
2998 for (int i = 0; i < CPSW_SLAVECNT; ++i)
2999 {
3000 pRegs->Slave[i] = (PCPSW_SLAVE_REGS) (dwBase + pPCfg->slave[i].dwCpswSlaveOffs);
3001 pRegs->Sliver[i] = (PCPSW_SLIVER_REGS) (dwBase + pPCfg->slave[i].dwCpswSliverOffs);
3002 }
3004 pRegs->SelectedSlave = pRegs->Slave[dwPortIdx];
3005 pRegs->SelectedSliver = pRegs->Sliver[dwPortIdx];
3006 }
3008 static void CPSWCheckId(PT_CPSW_INTERNAL pAdapter)
3009 {
3010 PCPSW_REGS pReg = pAdapter->regs.Cpsw;
3011 EC_T_DWORD dwIdReg = R32(pReg->CPSW_IdVer);
3013 EC_T_DWORD dwId = (dwIdReg >> 16) & 0xFFFF;
3014 EC_T_DWORD dwRtlVer = (dwIdReg >> 11) & 0x1F;
3015 EC_T_DWORD dwMajVer = (dwIdReg >> 8) & 0x7;
3016 EC_T_DWORD dwMinVer = dwIdReg & 0xFF;
3018 if (dwId == CPSW_ID_IDENT)
3019 {
3020 INF("CPSW3G found. ");
3021 }
3022 else
3023 {
3024 INF("No CPSW3G found (Unknown HW-Id). ");
3025 }
3027 INF("HW-Id: 0x%04x, RTL: %d, Major: %d, Minor: 0x%x\n",
3028 dwId, dwRtlVer, dwMajVer, dwMinVer);
3030 #ifdef DEBUG
3031 // Sanity check
3032 {
3033 EC_T_LINK_PLATFORMDATA_CPSW *pPCfg = &pAdapter->oInitParms.oPlatCfg;
3034 PCPSW_REGSET pRegs = &pAdapter->regs;
3036 EC_T_DWORD cpswId = R32(pRegs->Cpsw->CPSW_IdVer) >> 16;
3037 EC_T_DWORD aleId = R32(pRegs->Ale->ALE_IdVer) >> 16;
3038 EC_T_DWORD txId = R32(pRegs->Dma->Tx_Idver) >> 16;
3039 EC_T_DWORD ssId = R32(pRegs->Ss->IDVER) >> 16;
3040 EC_T_DWORD mdioId = (R32(pRegs->Mdio->Version) >> 16) & 0xFF;
3041 EC_T_DWORD p0MaxBlk = R32(pRegs->Host->P0_Max_blks);
3042 EC_T_DWORD p1MaxBlk = R32(pRegs->Slave[0]->Max_Blks);
3043 EC_T_DWORD p2MaxBlk = R32(pRegs->Slave[1]->Max_Blks);
3044 EC_T_DWORD sliverId0 = R32(pRegs->Sliver[0]->SL_IDVER) >> 16;
3045 EC_T_DWORD sliverId1 = R32(pRegs->Sliver[1]->SL_IDVER) >> 16;
3048 DBG("Register offsets: CPSW %x, Host %x, ALE %x, CPDMA %x, StateRAM %x, SS %x, MDIO %x, BD %x, "
3049 "Slave0 %x, Slave1 %x, Sliver0 %x, Sliver1 %x\n",
3050 0,
3051 pPCfg->dwHostPortOffs,
3052 pPCfg->dwCpswAleOffs,
3053 pPCfg->dwCpswCpdmaOffs,
3054 pPCfg->dwCpdmaStateramOffs,
3055 pPCfg->dwCpswSsOffs,
3056 pPCfg->dwMdioOffs,
3057 pPCfg->dwBdRamOffs,
3058 pPCfg->slave[0].dwCpswSlaveOffs,
3059 pPCfg->slave[1].dwCpswSlaveOffs,
3060 pPCfg->slave[0].dwCpswSliverOffs,
3061 pPCfg->slave[1].dwCpswSliverOffs
3062 );
3064 DBG("Subsystem ID's: CPSW %x, ALE %x, TX %x, SS %x, MDIO %x, Host %x, "
3065 "Slave0 %x, Slave1 %x, Sliver0 %x, Sliver1 %x\n",
3066 cpswId, aleId, txId, ssId, mdioId, p0MaxBlk,
3067 p1MaxBlk, p2MaxBlk, sliverId0, sliverId1);
3069 if (cpswId == 0x19 &&
3070 aleId == 0x29 &&
3071 txId == 0x18 &&
3072 (ssId == 0x4EDB || ssId == 0x4EDA) &&
3073 mdioId == 0x7 &&
3074 p0MaxBlk == 0x104 && // Valid after reset!
3075 p1MaxBlk == 0x113 && // "
3076 p2MaxBlk == 0x113 && // "
3077 sliverId0 == 0x17 &&
3078 sliverId1 == 0x17)
3079 {
3080 DBG("Register mapping valid\n");
3081 }
3082 else
3083 {
3084 DBG("!!! Register mapping invalid\n");
3085 }
3087 }
3088 #endif
3089 }
3091 static void CPSWCReadMacId(PT_CPSW_INTERNAL pAdapter)
3092 {
3093 EC_T_LINK_PLATFORMDATA_CPSW *pPCfg = &pAdapter->oInitParms.oPlatCfg;
3094 EC_T_DWORD ioaddr = (EC_T_DWORD)LinkOsMapMemory((EC_T_BYTE *)pPCfg->dwCtlModuleBase, 0x2000);
3095 if (ioaddr == 0)
3096 {
3097 ERR("Map CTL-Module failed\n");
3098 return;
3099 }
3101 EC_T_DWORD ioaddrChId = ioaddr + CPSWPortIdx(pAdapter) * 8;
3103 if (pAdapter->oInitParms.oPlatCfg.dwCtlModuleBase == AM57xx_pdata.dwCtlModuleBase)
3104 {
3105 EC_T_DWORD dwReg0 = r32((volatile EC_T_DWORD *)(ioaddrChId + CTRL_CORE_MAC_ID_SW_0));
3106 EC_T_DWORD dwReg1 = r32((volatile EC_T_DWORD *)(ioaddrChId + CTRL_CORE_MAC_ID_SW_1));
3107 pAdapter->abyStationAddress[0] = (EC_T_BYTE)((dwReg1 >> 16U) & 0xFFU);
3108 pAdapter->abyStationAddress[1] = (EC_T_BYTE)((dwReg1 >> 8U ) & 0xFFU);
3109 pAdapter->abyStationAddress[2] = (EC_T_BYTE)((dwReg1 ) & 0xFFU);
3110 pAdapter->abyStationAddress[3] = (EC_T_BYTE)((dwReg0 >> 16U) & 0xFFU);
3111 pAdapter->abyStationAddress[4] = (EC_T_BYTE)((dwReg0 >> 8U ) & 0xFFU);
3112 pAdapter->abyStationAddress[5] = (EC_T_BYTE)((dwReg0 )& 0xFFU);
3113 }
3114 else
3115 {
3116 *((EC_T_DWORD *)pAdapter->abyStationAddress) = r32((volatile EC_T_DWORD *)(ioaddrChId + CTLM_MACID0_HI));
3117 *((EC_T_WORD *)(pAdapter->abyStationAddress + 4)) = (EC_T_WORD)r32((volatile EC_T_DWORD *)(ioaddrChId + CTLM_MACID0_LO));
3118 }
3120 LinkOsUnmapMemory((EC_T_BYTE *)ioaddr, 0x2000);
3121 }
3123 #ifdef CPSW_ENABLE_CLOCKS
3124 static void CPSWClkEnable(PT_CPSW_INTERNAL pAdapter)
3125 {
3126 /* clocks should be not enabled for am387x chipset */
3127 if (pAdapter->oInitParms.oPlatCfg.dwCtlModuleBase == AM387x_pdata.dwCtlModuleBase
3128 && pAdapter->oInitParms.oPlatCfg.dwHostPortOffs == AM387x_pdata.dwHostPortOffs)
3129 {
3130 return;
3131 }
3133 EC_T_DWORD ioaddr = (EC_T_DWORD)LinkOsMapMemory((EC_T_BYTE *)SOC_PRCM_REGS, 0x1000);
3134 if (ioaddr == 0)
3135 {
3136 ERR("clock en failed\n");
3137 return;
3138 }
3140 /* enable both clocks registers and wait after that */
3141 w32((volatile EC_T_DWORD *)(ioaddr + CM_PER_CPGMAC0_CLKCTRL), CM_PER_CPGMAC0_CLKCTRL_MODULEMODE_ENABLE);
3142 w32((volatile EC_T_DWORD *)(ioaddr + CM_PER_CPSW_CLKSTCTRL), CM_PER_CPSW_CLKSTCTRL_CLKTRCTRL_SW_WKUP);
3144 size_t counter = 0;
3145 while(0 != (r32((volatile EC_T_DWORD *)(ioaddr + CM_PER_CPGMAC0_CLKCTRL))
3146 & CM_PER_CPGMAC0_CLKCTRL_IDLEST))
3147 {
3148 counter++;
3149 if ( counter > 1000000 ) /* do not wait forever */
3150 break;
3151 }
3153 counter = 0;
3154 while(0 == (r32((volatile EC_T_DWORD *)(ioaddr + CM_PER_CPSW_CLKSTCTRL))
3155 & CM_PER_CPSW_CLKSTCTRL_CLKACTIVITY_CPSW_125MHZ_GCLK))
3156 {
3157 counter++;
3158 if ( counter > 1000000 ) /* do not wait forever */
3159 break;
3160 }
3162 LinkOsUnmapMemory((EC_T_BYTE *)ioaddr, 0x1000);
3163 }
3164 #endif
3166 #ifdef TRACE
3167 /********************************************************************************/
3168 /** \brief Tracing of a received frame.
3169 *
3170 * \return N/A.
3171 */
3172 static void emllDumpFrame
3173 ( EC_T_BOOL bTxFrame, /* [in] EC_TRUE if it is a tx frame */
3174 EC_T_BYTE* pbyFrame, /* [in] ethernet frame */
3175 EC_T_DWORD dwSize /* [in] frame size */
3176 )
3177 {
3178 EC_T_DWORD dwCnt;
3179 const char* szPrefix;
3180 static EC_T_DWORD s_dwTxFrameCnt = 0;
3181 static EC_T_DWORD s_dwRxFrameCnt = 0;
3182 EC_T_DWORD dwFrameCnt;
3184 if( bTxFrame )
3185 {
3186 s_dwTxFrameCnt++;
3187 szPrefix="SND";
3188 dwFrameCnt=s_dwTxFrameCnt;
3189 }
3190 else
3191 {
3192 s_dwRxFrameCnt++;
3193 szPrefix="RCV";
3194 dwFrameCnt=s_dwRxFrameCnt;
3195 }
3197 PRINT( "\n------------------------------------------------------\n" );
3198 PRINT( "FRAME-%s[%d](%d):", szPrefix, dwSize, dwFrameCnt );
3199 for( dwCnt = 0; dwCnt < dwSize; dwCnt++ )
3200 {
3201 if( (dwCnt % 16) == 0 )
3202 {
3203 PRINT( "\n[%03X] ", dwCnt );
3204 }
3205 PRINT( "%02X ", pbyFrame[dwCnt] );
3206 }
3207 PRINT( "\n" );
3208 }
3209 #endif
3214 #if defined USE_CPSW_TEST || 0
3216 #define CFG_AM33XX 1
3217 #define TXBURST_FRAMES 4 // Number of frames to send per cycle
3219 CCALLING void emllCPSWTest(int argc, char **argv);
3220 EC_T_DWORD emllCPSWTestFrameRcv(void* pvContext, struct _EC_T_LINK_FRAMEDESC* pLinkFrameDesc, EC_T_BOOL* pbFrameProcessed);
3221 EC_T_DWORD emllCPSWTestNotify(EC_T_DWORD dwCode, struct _EC_T_LINK_NOTIFYPARMS* pParms);
3223 void* pvLLInstance;
3225 static EC_T_BYTE S_abyFrameData[60] =
3226 {
3227 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Dest Mac */ /*0-5*/
3228 0xD0, 0xAD, 0xBE, 0xEF, 0xBA, 0xBE, /* Src Mac */ /*6-11*/
3229 0x88, 0xa4, /* Type ECAT */ /*12-13*/
3230 0x0e, 0x10, /* E88A4 Length 0x0e, Type ECAT (0x1) */ /*14-15*/
3231 0x01, /* APRD */ /*16*/
3232 0x80, /* Index */ /*17*/
3233 0x00, 0x00, /* Slave Address */ /*18-19*/
3234 0x30, 0x01, /* Offset Address */ /*20-21*/
3235 0x04, 0x00, /* Length - Last sub command */ /*22-23*/
3236 0x00, 0x00, /* Interrupt */ /*24-25*/
3237 0x00, 0x00, /* Data */ /*26-27*/
3238 0x00, 0x00, /* Data 2 */ /*28-29*/
3239 0x00, 0x00 /* Working Counter */ /*30-31*/
3240 };
3242 static EC_T_BOOL s_bNotUseDmaBuffers = EC_TRUE;
3244 #if !(defined STARTERWARE_NOOS) && !(defined EC_VERSION_SYSBIOS)
3245 // For Windows CE, change entry point to mainACRTStartup under Linker/Advanced settings in VS
3246 CCALLING int main(int argc, char **argv)
3247 {
3248 emllCPSWTest(argc, argv);
3249 PRINT("Quit\n");
3250 return 0;
3251 }
3252 #endif
3254 EC_T_BOOL DbgMsgHook(const EC_T_CHAR* szFormat, EC_T_LINKVALIST vaArgs)
3255 {
3256 vfprintf(stderr, szFormat, vaArgs);
3257 fflush(stderr);
3258 return EC_FALSE;
3259 }
3261 static EC_T_LINKSTATUS emllCPSWTestGetStatus(void *pvLLInstance) // Query PHY's link status and reconfigure MAC
3262 {
3263 EcLinkIoctl(pvLLInstance, EC_LINKIOCTL_UPDATE_LINKSTATUS, 0); // Update link status
3264 return EcLinkGetStatus(pvLLInstance);
3265 }
3267 static EC_T_BOOL sendFrame(
3268 EC_T_BYTE *frame, EC_T_DWORD frameLen,
3269 EC_T_BYTE dstAddr[6], EC_T_BYTE srcAddr[6])
3270 {
3271 EC_T_LINK_FRAMEDESC oSendFrame = {0};
3272 EC_T_DWORD dwStatus;
3274 if (!s_bNotUseDmaBuffers)
3275 {
3276 dwStatus = EcLinkAllocSendFrame(pvLLInstance, &oSendFrame, frameLen);
3277 if (dwStatus != EC_E_NOERROR)
3278 {
3279 PRINT( "EcLinkAllocSendFrame returned error 0x%x\n", dwStatus);
3280 return EC_FALSE;
3281 }
3283 // Copy frame into DMA buffer
3284 memcpy(oSendFrame.pbyFrame, frame, frameLen);
3286 // Dst addr
3287 for (int j = 0; j < 6; ++j) oSendFrame.pbyFrame[j] = dstAddr[j];
3288 // Src addr
3289 for (int j = 0; j < 6; ++j) oSendFrame.pbyFrame[6 + j] = srcAddr[j];
3290 }
3291 else
3292 {
3293 oSendFrame.pbyFrame = frame;
3294 oSendFrame.dwSize = frameLen;
3295 }
3297 dwStatus = EcLinkSendAndFreeFrame(pvLLInstance, &oSendFrame);
3298 if (dwStatus != EC_E_NOERROR)
3299 {
3300 PRINT( "EcLinkSendAndFreeFrame returned error 0x%x\n", dwStatus);
3301 return EC_FALSE;
3302 }
3304 return EC_TRUE;
3305 }
3307 static EC_T_BOOL sendAllFrames(
3308 EC_T_BYTE *frame, EC_T_DWORD frameLen,
3309 EC_T_BYTE dstAddr[6], EC_T_BYTE srcAddr[6],
3310 EC_T_DWORD *frameCounter, int txFrames)
3311 {
3312 for (int j = 0; j < txFrames; ++j)
3313 {
3314 if (!sendFrame(frame, frameLen, dstAddr, srcAddr)) return EC_FALSE;
3315 (*frameCounter)++;
3316 }
3317 return EC_TRUE;
3318 }
3320 static void IoCtrl(EC_T_DWORD dwCode)
3321 {
3322 EC_T_DWORD dwErr = EcLinkIoctl(pvLLInstance, dwCode, EC_NULL);
3323 if (dwErr != EC_E_NOERROR)
3324 {
3325 PRINT( "EcLinkIoctl returned error 0x%x\n", dwErr);
3326 }
3327 }
3329 void emllCPSWTest(int argc, char **argv)
3330 {
3331 EC_T_LINK_PARMS_CPSW LinkParamCPSW;
3332 EC_T_DWORD dwStatus;
3333 EC_T_LINK_FRAMEDESC oRecvFrame = {0};
3334 #if 0
3335 EC_T_BOOL bLinkOKFlag = EC_FALSE;
3336 #endif
3337 EC_T_DWORD i;
3338 EC_T_BYTE dstAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
3339 EC_T_BYTE srcAddress[] = { 0xD0, 0xAD, 0xBE, 0xEF, 0xBA, 0xBE };
3340 int macbuf[6];
3341 EC_T_DWORD dwInstance = 0;
3342 EC_T_DWORD intFlag = 0;
3343 EC_T_BOOL bMaster = EC_FALSE;
3344 EC_T_DWORD rxtxMask = 0;
3345 EC_T_DWORD numframes = 0;
3346 EC_T_DWORD txFrames = 0;
3347 EC_T_DWORD rxFrames = 0;
3348 EC_T_DWORD oldRxFrames = 0;
3350 #define RXMSK 1
3351 #define TXMSK 2
3353 LinkOsAddDbgMsgHook(DbgMsgHook);
3355 PRINT("emllCPSWTest test program\n");
3357 if (argc < 4)
3358 {
3359 PRINT(
3360 "Usage: emllCPSWTest <CPSW-Port> <IntFlag> [m | s] { <rxtx> <numframes> <dstaddr> <srcaddr>}\n"
3361 " CPSW-Port: 1 first, 2 second.\n"
3362 " IntFlag: [0 | 1] 0 Polling, 1 Interrupt\n"
3363 " m := Master (Init MAC), s := Slave (for 2nd instance)\n"
3364 " rxtx := 1 rx, 2 tx, 3 rx+tx\n"
3365 " numframes := TX-Frames, 0 for infinite\n"
3366 " dstaddr := Destination MAC in format xx:xx:xx:xx:xx:xx\n"
3367 " srcaddr := Destination MAC in format xx:xx:xx:xx:xx:xx\n"
3368 "\n"
3369 );
3370 return;
3371 }
3373 dwInstance = (EC_T_DWORD)atoi(argv[1]);
3374 intFlag = (EC_T_DWORD)atoi(argv[2]);
3375 bMaster = argv[3][0] == 'm';
3376 rxtxMask = argc >= 5 ? atoi(argv[4]) : RXMSK | TXMSK;
3377 rxtxMask &= 0x3;
3378 numframes = argc >= 6 ? atoi(argv[5]) : 0;
3380 if (dwInstance < 1 || dwInstance > 2 || intFlag > 1 || strlen(argv[3]) != 1 || (argv[3][0] != 'm' && argv[3][0] != 's'))
3381 {
3382 PRINT("Invalid usage\n");
3383 return;
3384 }
3386 if (argc >= 7)
3387 {
3388 sscanf(argv[6], "%2x:%2x:%2x:%2x:%2x:%2x", // %x needs DWORD buffers, not BYTE!
3389 macbuf+0, macbuf+1, macbuf+2, macbuf+3, macbuf+4, macbuf+5);
3390 for (int i = 0; i < 6; ++i) dstAddress[i] = (EC_T_BYTE) (macbuf[i] & 0xFF);
3391 }
3393 if (argc >= 8)
3394 {
3395 sscanf(argv[7], "%2x:%2x:%2x:%2x:%2x:%2x", // %x needs DWORD buffers, not BYTE!
3396 macbuf+0, macbuf+1, macbuf+2, macbuf+3, macbuf+4, macbuf+5);
3397 for (int i = 0; i < 6; ++i) srcAddress[i] = (EC_T_BYTE) (macbuf[i] & 0xFF);
3398 }
3400 PRINT( "Instance %d, Flags [%s] [%s] [%s %s], TX-Frames %d\n, ",
3401 dwInstance,
3402 intFlag ? "Interrupt" : "Polling",
3403 bMaster ? "Master" : "Slave",
3404 (rxtxMask & RXMSK) ? "RX" : "--",
3405 (rxtxMask & TXMSK) ? "TX" : "--",
3406 numframes);
3408 /* initialization */
3409 memset(&LinkParamCPSW, 0, sizeof(LinkParamCPSW));
3411 #if CFG_AM387X
3412 memcpy(&LinkParamCPSW.oPlatCfg, &AM387x_pdata, sizeof(AM387x_pdata));
3413 #elif (defined SOC_AM572x)
3414 memcpy(&LinkParamCPSW.oPlatCfg, &AM57xx_pdata, sizeof(AM57xx_pdata));
3415 #elif CFG_AM33XX
3416 memcpy(&LinkParamCPSW.oPlatCfg, &AM33xx_pdata, sizeof(AM33xx_pdata));
3417 #else
3418 # error No board configuration
3419 #endif
3420 LinkParamCPSW.dwPhyAddr = dwInstance - 1; // 0 -> Port1, 1 -> Port2
3421 #if (defined EC_VERSION_SYSBIOS)
3422 #if !(defined SOC_AM572x)
3423 LinkParamCPSW.dwPhyAddr = (dwInstance == 1) ? 1 : 3;
3424 #endif
3425 LinkParamCPSW.ePhyConnection = eCpswPhySource_RGMII;
3426 #endif
3427 LinkParamCPSW.linkParms.dwInstance = dwInstance;
3428 LinkParamCPSW.dwPortPrio = 1;// /*bMaster ? 0 : 1*/ dwInstance - 1;
3429 LinkParamCPSW.bPhyRestartAutoNegotiation = EC_TRUE;
3430 LinkParamCPSW.bNotUseDmaBuffers = s_bNotUseDmaBuffers;
3431 LinkParamCPSW.bMaster = bMaster;
3432 LinkParamCPSW.linkParms.dwSignature = EC_LINK_PARMS_SIGNATURE_CPSW;
3433 LinkParamCPSW.linkParms.eLinkMode = intFlag ? EcLinkMode_INTERRUPT : EcLinkMode_POLLING;
3435 LinkParamCPSW.ePhyConnection = eCpswPhySource_RGMII;
3437 dwStatus = EcLinkOpen( &LinkParamCPSW, emllCPSWTestFrameRcv, emllCPSWTestNotify, EC_NULL, &pvLLInstance );
3438 if (dwStatus != EC_E_NOERROR)
3439 {
3440 PRINT( "emllCPSWTest: error 0x%x in EcLinkOpen!\n", dwStatus );
3441 return;
3442 }
3444 /* wait for link */
3445 while (emllCPSWTestGetStatus(pvLLInstance) != eLinkStatus_OK)
3446 {
3447 LinkOsSleep(2000);
3448 PRINT( "No Link\n");
3449 }
3451 /* Send and receive frames */
3452 LinkOsSleep(1);
3453 for (i = 0; numframes == 0 || i < numframes; ++i)
3454 {
3455 if (rxtxMask & TXMSK)
3456 {
3457 IoCtrl(EC_LINKIOCTL_SENDACYCLICFRAMES);
3458 if (!sendAllFrames(
3459 S_abyFrameData, sizeof(S_abyFrameData),
3460 dstAddress, srcAddress, &txFrames, TXBURST_FRAMES)) goto Exit;
3461 IoCtrl(EC_LINKIOCTL_FLUSHFRAMES);
3462 }
3464 oldRxFrames = rxFrames;
3466 LinkOsSleep(1); // Wait for next cycle
3468 #if 0
3469 /* Check link status */
3470 if (bLinkOKFlag && emllCPSWTestGetStatus(pvLLInstance) != eLinkStatus_OK)
3471 {
3472 PRINT( "Link Down\n");
3473 bLinkOKFlag = EC_FALSE;
3474 }
3475 if (! bLinkOKFlag && emllCPSWTestGetStatus(pvLLInstance) == eLinkStatus_OK)
3476 {
3477 PRINT( "Link Up. Speed %u MBit\n", EcLinkGetSpeed(pvLLInstance));
3478 bLinkOKFlag = EC_TRUE;
3479 }
3480 #endif
3482 if (rxtxMask & RXMSK)
3483 {
3484 /* receive frame(s) */
3485 for (;;)
3486 {
3487 dwStatus = EcLinkRecvFrame(pvLLInstance, &oRecvFrame);
3488 if (dwStatus != EC_E_NOERROR)
3489 {
3490 PRINT( "EcLinkRecvFrame returned error 0x%x\n", dwStatus);
3491 goto Exit;
3492 }
3494 if (oRecvFrame.pbyFrame == EC_NULL) break;
3496 rxFrames++;
3498 #ifdef TRACE
3499 // Print frame
3500 emllDumpFrame(EC_FALSE, (EC_T_BYTE *) oRecvFrame.pbyFrame, oRecvFrame.dwSize);
3501 #endif
3502 // Release frame
3503 EcLinkFreeRecvFrame(pvLLInstance, &oRecvFrame);
3504 }
3505 }
3507 /* simulated frame processing */
3508 LinkOsSysDelay(50);
3510 if ( ( rxtxMask == RXMSK && rxFrames != oldRxFrames ) // Print if new frame received
3511 || ( rxtxMask == (RXMSK | TXMSK) && i > 0 && (i % 5000) == 0 ) ) // Print each 5s
3512 {
3513 PRINT("Cycle %d: TxFrames %d, RxFrames %d\n", i, txFrames, rxFrames);
3514 }
3515 }
3517 /* debug */
3518 PRINT("Graceful shutdown. TxFrames %d, RxFrames %d\n", txFrames, rxFrames);
3520 Exit:
3522 dwStatus = EcLinkClose( pvLLInstance );
3523 if( dwStatus != EC_E_NOERROR )
3524 {
3525 PRINT( "EcLinkClose returned error 0x%x\n", dwStatus );
3526 return;
3527 }
3528 }
3530 EC_T_DWORD emllCPSWTestFrameRcv
3531 ( void* pvContext,
3532 struct _EC_T_LINK_FRAMEDESC* pLinkFrameDesc,
3533 EC_T_BOOL* pbFrameProcessed
3534 )
3535 {
3536 PT_CPSW_INTERNAL pAdapter = (PT_CPSW_INTERNAL) pvLLInstance;
3537 EC_UNREFPARM(pvContext);
3538 EC_UNREFPARM(pbFrameProcessed);
3540 #ifdef TRACE
3541 /* print frame */
3542 emllDumpFrame(EC_FALSE, (EC_T_BYTE *) pLinkFrameDesc->pbyFrame, pLinkFrameDesc->dwSize);
3543 #endif
3545 /* release frame */
3546 EcLinkFreeRecvFrame(pAdapter, pLinkFrameDesc);
3548 return EC_E_NOERROR;
3549 }
3551 EC_T_DWORD emllCPSWTestNotify
3552 ( EC_T_DWORD dwCode,
3553 struct _EC_T_LINK_NOTIFYPARMS* pParms
3554 )
3555 {
3556 EC_UNREFPARM(dwCode);
3557 EC_UNREFPARM(pParms);
3558 return EC_E_NOERROR;
3559 }
3561 #endif /* USE_CPSW_TEST */
3564 /*-END OF SOURCE FILE--------------------------------------------------------*/