summaryrefslogtreecommitdiff
path: root/cpsw/src/netif
diff options
context:
space:
mode:
Diffstat (limited to 'cpsw/src/netif')
-rwxr-xr-xcpsw/src/netif/FILES1
-rwxr-xr-xcpsw/src/netif/cache.c249
-rwxr-xr-xcpsw/src/netif/cp15.S588
-rwxr-xr-xcpsw/src/netif/cpsw.c1545
-rwxr-xr-xcpsw/src/netif/cpsw_bb.c161
-rwxr-xr-xcpsw/src/netif/cpswif.c2999
-rw-r--r--cpsw/src/netif/delay.c6
-rwxr-xr-xcpsw/src/netif/mdio.c209
-rwxr-xr-xcpsw/src/netif/mmu.c184
-rwxr-xr-xcpsw/src/netif/phy.c402
10 files changed, 6344 insertions, 0 deletions
diff --git a/cpsw/src/netif/FILES b/cpsw/src/netif/FILES
new file mode 100755
index 0000000..0411124
--- /dev/null
+++ b/cpsw/src/netif/FILES
@@ -0,0 +1 @@
+cpswif.c - lwIP Ethernet interface for CPSW based devices.
diff --git a/cpsw/src/netif/cache.c b/cpsw/src/netif/cache.c
new file mode 100755
index 0000000..699961b
--- /dev/null
+++ b/cpsw/src/netif/cache.c
@@ -0,0 +1,249 @@
+/**
+ * \file cache.c
+ *
+ * \brief APIs for configuring Cache
+ *
+ * This file contains the APIs for configuring ARMv7a Cache
+*/
+
+/*
+* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+*/
+/*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+#include "cache.h"
+#include "cp15.h"
+
+/*****************************************************************************
+** INTERNAL MACRO DEFINITIONS
+******************************************************************************/
+#define CORTEX_A8_L2EN (0x02)
+#define PRIMARY_PART_CORTEX_A8 (0xC08)
+
+/*****************************************************************************
+** FUNCTION DEFINITIONS
+******************************************************************************/
+/**
+ * \brief Disables Cache. The levels/type of Cache to be disabled
+ * is passed as parameter.
+ *
+ * \param disFlag Caches to be disabled.
+ * 'disFlag' can take one of the below values. \n
+ * CACHE_ICACHE - To disable Instruction Cache \n
+ * CACHE_DCACHE - To disable Data/Unified Cache \n
+ * CACHE_ALL - To disable all levels of Cache
+ *
+ * \return None.
+ *
+ * \Note Disabling Data Cache disables Unified cache also, if present.
+ **/
+void CacheDisable(unsigned int disFlag)
+{
+ if(disFlag & CACHE_ICACHE)
+ {
+ /*
+ ** Disable I-Cache. The I-Cache invalidation is also done inside
+ ** CP15ICacheDisable().
+ */
+ CP15ICacheDisable();
+ }
+
+ /* Here D Cache Disabling disables Unified cache also */
+ if(disFlag & CACHE_DCACHE)
+ {
+ /*
+ ** Disable D-Cache. The D-Cache Clean and Invalidation is also done
+ ** inside CP15DCacheDisable().
+ */
+ CP15DCacheDisable();
+
+ /* For Cortex A8, L2EN has to be disabled for L2 Cache */
+ if(PRIMARY_PART_CORTEX_A8 == CP15MainIdPrimPartNumGet())
+ {
+ CP15AuxControlFeatureDisable(CORTEX_A8_L2EN);
+ }
+ }
+}
+
+/**
+ * \brief Enables Cache. The levels/type of Cache to be enabled
+ * is passed as parameter.
+ *
+ * \param enFlag Caches to be enabled.
+ * 'enFlag' can take one of the below values. \n
+ * CACHE_ICACHE - To enable Instruction Cache \n
+ * CACHE_DCACHE - To enable Data/Unified Cache \n
+ * CACHE_ALL - To enable all levels of Cache
+ *
+ * \return None.
+ *
+ * \Note Enabling Data Cache enables Unified cache also, if present.
+ **/
+void CacheEnable(unsigned int enFlag)
+{
+ if(enFlag & CACHE_ICACHE)
+ {
+ CP15ICacheFlush();
+ CP15ICacheEnable();
+ }
+
+ if(enFlag & CACHE_DCACHE)
+ {
+ /* For Cortex A8, L2EN has to be enabled for L2 Cache */
+ if(PRIMARY_PART_CORTEX_A8 == CP15MainIdPrimPartNumGet())
+ {
+ CP15AuxControlFeatureEnable(CORTEX_A8_L2EN);
+ }
+
+ CP15DCacheFlush();
+ CP15DCacheEnable();
+ }
+}
+
+/**
+ * \brief This API invalidates the entire I-Cache
+ *
+ * \param None
+ *
+ * \return None.
+ *
+ **/
+void CacheInstInvalidateAll(void)
+{
+ CP15ICacheFlush();
+}
+
+/**
+ * \brief This API invalidates a section of I-Cache.
+ *
+ * \param startAddr Starting address to be invalidated
+ * \param numBytes The number of bytes to be invalidated
+ *
+ * \return None.
+ *
+ **/
+void CacheInstInvalidateBuff(unsigned int startAddr, unsigned int numBytes)
+{
+ CP15ICacheFlushBuff(startAddr, numBytes);
+}
+
+/**
+ * \brief This API Cleans and Invalidates the entire Data Cache.
+ *
+ * \param None
+ *
+ * \return None.
+ *
+ **/
+void CacheDataCleanInvalidateAll(void)
+{
+ CP15DCacheCleanFlush();
+}
+
+/**
+ * \brief This API Cleans the entire Data Cache.
+ *
+ * \param None
+ *
+ * \return None.
+ *
+ **/
+void CacheDataCleanAll(void)
+{
+ CP15DCacheClean();
+}
+
+/**
+ * \brief This API Invalidates the entire Data Cache.
+ *
+ * \param None
+ *
+ * \return None.
+ *
+ **/
+void CacheDataInvalidateAll(void)
+{
+ CP15DCacheFlush();
+}
+
+/**
+ * \brief This API clean a section of D-Cache, upto PoC. This API
+ * can be used to make a buffer in D-Cache to be coherent
+ * with the memory. For example, If DMA engine has to access
+ * a memory area for transmitting, to make sure that the
+ * D-Cache values for the corresponding buffer is written to
+ * memory, this API can be used.
+ *
+ * \param startAddr Starting address of the buffer to be cleaned
+ * \param numBytes The number of bytes to be cleaned.
+ *
+ * \return None.
+ *
+ **/
+void CacheDataCleanBuff(unsigned int startAddr, unsigned int numBytes)
+{
+ CP15DCacheCleanBuff(startAddr, numBytes);
+}
+
+/**
+ * \brief This API invalidates a section of D-Cache till PoC. With this
+ * API, we can make sure that the next read of the buffer happens
+ * from memory. This is required if any DMA engine has updated
+ * the memory area with any data, other than from the D-Cache.
+ *
+ * \param startAddr Starting address of the buffer to be invalidated
+ * \param numBytes The number of bytes to be invalidated
+ *
+ * \return None.
+ *
+ **/
+void CacheDataInvalidateBuff(unsigned int startAddr, unsigned int numBytes)
+{
+ CP15DCacheFlushBuff(startAddr, numBytes);
+}
+
+/**
+ * \brief This API cleans and invalidates a section of D-Cache to PoC.
+ *
+ * \param startAddr Starting address of the buffer to be cleaned
+ * and invalidated
+ * \param numBytes The number of bytes to be cleaned and invalidated
+ *
+ * \return None.
+ *
+ **/
+void CacheDataCleanInvalidateBuff(unsigned int startAddr, unsigned int numBytes)
+{
+ CP15DCacheCleanFlushBuff(startAddr, numBytes);
+}
+
+/***************************** End Of File ***********************************/
+
diff --git a/cpsw/src/netif/cp15.S b/cpsw/src/netif/cp15.S
new file mode 100755
index 0000000..530288b
--- /dev/null
+++ b/cpsw/src/netif/cp15.S
@@ -0,0 +1,588 @@
+@******************************************************************************
+@
+@ cp15.S - CP15 coprocesser configuration APIs
+@
+@******************************************************************************
+@
+@ Copyright (C) 2010 Texas InSTRuments Incorporated - http://www.ti.com/
+@
+@
+@ RediSTRibution and use in source and binary forms, with or without
+@ modification, are permitted provided that the following conditions
+@ are met:
+@
+@ RediSTRibutions of source code must retain the above copyright
+@ notice, this list of conditions and the following disclaimer.
+@
+@ RediSTRibutions in binary form must reproduce the above copyright
+@ notice, this list of conditions and the following disclaimer in the
+@ documentation and/or other materials provided with the
+@ diSTRibution.
+@
+@ Neither the name of Texas InSTRuments Incorporated nor the names of
+@ its contributors may be used to endorse or promote products derived
+@ from this software without specific prior written permission.
+@
+@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+@
+@******************************************************************************
+
+@****************************** Global Symbols*********************************
+ .global CP15ICacheDisable
+ .global CP15DCacheDisable
+ .global CP15ICacheEnable
+ .global CP15DCacheEnable
+ .global CP15ICacheFlush
+ .global CP15DCacheCleanFlush
+ .global CP15DCacheClean
+ .global CP15DCacheFlush
+ .global CP15DCacheCleanBuff
+ .global CP15DCacheCleanFlushBuff
+ .global CP15DCacheFlushBuff
+ .global CP15ICacheFlushBuff
+ .global CP15Ttb0Set
+ .global CP15TlbInvalidate
+ .global CP15MMUDisable
+ .global CP15MMUEnable
+ .global CP15VectorBaseAddrSet
+ .global CP15BranchPredictorInvalidate
+ .global CP15BranchPredictionEnable
+ .global CP15BranchPredictionDisable
+ .global CP15DomainAccessClientSet
+ .global CP15ControlFeatureDisable
+ .global CP15ControlFeatureEnable
+ .global CP15TtbCtlTtb0Config
+ .global CP15AuxControlFeatureEnable
+ .global CP15AuxControlFeatureDisable
+ .global CP15MainIdPrimPartNumGet
+
+@**************************** Code section ************************************
+ .text
+
+ @ This code is assembled for ARM instructions
+ .code 32
+
+
+@*****************************************************************************
+@ This API disable the InSTRuction cache.
+@*****************************************************************************
+CP15ICacheDisable:
+ PUSH {lr}
+ MRC p15, #0, r0, c1, c0, #0
+ BIC r0, r0, #0x00001000
+ MCR p15, #0, r0, c1, c0, #0
+ BL CP15ICacheFlush
+ POP {lr}
+ BX lr
+
+@*****************************************************************************
+@ This API disable the Data cache.
+@*****************************************************************************
+CP15DCacheDisable:
+ PUSH {r4-r11, lr}
+ MRC p15, #0, r0, c1, c0, #0
+ BIC r0, r0, #0x00000004
+ MCR p15, #0, r0, c1, c0, #0
+ BL CP15DCacheCleanFlush
+ POP {r4-r11, lr}
+ BX lr
+
+@*****************************************************************************
+@ This API enables I-cache
+@*****************************************************************************
+CP15ICacheEnable:
+ MRC p15, #0, r0, c1, c0, #0
+ ORR r0, r0, #0x00001000
+ MCR p15, #0, r0, c1, c0, #0
+ BX lr
+
+@*****************************************************************************
+@ This API enable the Data cache.
+@*****************************************************************************
+CP15DCacheEnable:
+ MRC p15, #0, r0, c1, c0, #0
+ ORR r0, r0, #0x00000004
+ MCR p15, #0, r0, c1, c0, #0
+ BX lr
+
+@*****************************************************************************
+@ This API Invalidates the entire Data/Unified Cache
+@*****************************************************************************
+CP15DCacheFlush:
+ PUSH {r4-r11}
+ DMB
+ MRC p15, #1, r0, c0, c0, #1 @ Read CLID register
+ ANDS r3, r0, #0x7000000 @ Get Level of Coherency
+ MOV r3, r3, lsr #23
+ BEQ ffinished
+ MOV r10, #0
+floop1:
+ ADD r2, r10, r10, lsr #1
+ MOV r1, r0, lsr r2
+ AND r1, r1, #7
+ CMP r1, #2
+ BLT fskip
+ MCR p15, #2, r10, c0, c0, #0
+ ISB
+ MRC p15, #1, r1, c0, c0, #0
+ AND r2, r1, #7
+ ADD r2, r2, #4
+ LDR r4, _FLD_MAX_WAY
+ ANDS r4, r4, r1, lsr #3
+ CLZ r5, r4
+ LDR r7, _FLD_MAX_IDX
+ ANDS r7, r7, r1, lsr #13
+floop2:
+ MOV r9, r4
+floop3:
+ ORR r11, r10, r9, lsl r5
+ ORR r11, r11, r7, lsl r2
+ MCR p15, #0, r11, c7, c6, #2
+ SUBS r9, r9, #1
+ BGE floop3
+ SUBS r7, r7, #1
+ BGE floop2
+fskip:
+ ADD r10, r10, #2
+ CMP r3, r10
+ BGT floop1
+
+ffinished:
+ DSB
+ ISB
+ POP {r4-r11}
+ BX lr
+
+
+@*****************************************************************************
+@ This API cleans the entire D Cache to PoC
+@*****************************************************************************
+CP15DCacheClean:
+ PUSH {r4-r11}
+ DMB
+ MRC p15, #1, r0, c0, c0, #1 @ Read CLID register
+ ANDS r3, r0, #0x7000000 @ Get Level of Coherency
+ MOV r3, r3, lsr #23
+ BEQ cfinished
+ MOV r10, #0
+cloop1:
+ ADD r2, r10, r10, lsr #1
+ MOV r1, r0, lsr r2
+ AND r1, r1, #7
+ CMP r1, #2
+ BLT cskip
+ MCR p15, #2, r10, c0, c0, #0
+ ISB
+ MRC p15, #1, r1, c0, c0, #0
+ AND r2, r1, #7
+ ADD r2, r2, #4
+ LDR r4, _FLD_MAX_WAY
+ ANDS r4, r4, r1, lsr #3
+ CLZ r5, r4
+ LDR r7, _FLD_MAX_IDX
+ ANDS r7, r7, r1, lsr #13
+cloop2:
+ MOV r9, r4
+cloop3:
+ ORR r11, r10, r9, lsl r5
+ ORR r11, r11, r7, lsl r2
+ MCR p15, #0, r11, c7, c10, #2
+ SUBS r9, r9, #1
+ BGE cloop3
+ SUBS r7, r7, #1
+ BGE cloop2
+cskip:
+ ADD r10, r10, #2
+ CMP r3, r10
+ BGT cloop1
+
+cfinished:
+ DSB
+ ISB
+ POP {r4-r11}
+ BX lr
+
+@*****************************************************************************
+@ This API cleans and invalidates the entire D Cache to PoC
+@*****************************************************************************
+CP15DCacheCleanFlush:
+ PUSH {r4-r11}
+ DMB
+ MRC p15, #1, r0, c0, c0, #1 @ Read CLID register
+ ANDS r3, r0, #0x7000000 @ Get Level of Coherency
+ MOV r3, r3, lsr #23
+ BEQ finished
+ MOV r10, #0
+loop1:
+ ADD r2, r10, r10, lsr #1
+ MOV r1, r0, lsr r2
+ AND r1, r1, #7
+ CMP r1, #2
+ BLT skip
+ MCR p15, #2, r10, c0, c0, #0
+ ISB
+ MRC p15, #1, r1, c0, c0, #0
+ AND r2, r1, #7
+ ADD r2, r2, #4
+ LDR r4, _FLD_MAX_WAY
+ ANDS r4, r4, r1, lsr #3
+ CLZ r5, r4
+ LDR r7, _FLD_MAX_IDX
+ ANDS r7, r7, r1, lsr #13
+loop2:
+ MOV r9, r4
+loop3:
+ ORR r11, r10, r9, lsl r5
+ ORR r11, r11, r7, lsl r2
+ MCR p15, #0, r11, c7, c14, #2
+ SUBS r9, r9, #1
+ BGE loop3
+ SUBS r7, r7, #1
+ BGE loop2
+skip:
+ ADD r10, r10, #2
+ CMP r3, r10
+ BGT loop1
+
+finished:
+ DSB
+ ISB
+ POP {r4-r11}
+ BX lr
+
+@*****************************************************************************
+@ This API invalidates entire I Cache
+@*****************************************************************************
+CP15ICacheFlush:
+ MOV r0, #0
+ MCR p15, #0, r0, c7, c5, #0
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API cleans the D-cache/Unified lines corresponding to the buffer
+@ pointer upto the specified length to PoC.
+@ r0 - Start Address
+@ r1 - Number of bytes to be cleaned
+@*****************************************************************************
+CP15DCacheCleanBuff:
+ PUSH {r14}
+ ADD r14, r0, r1 @ Calculate the end address
+ DMB
+ MRC p15, #0, r2, c0, c0, #1 @ Read Cache Type Register
+ UBFX r2, r2, #16, #4 @ Extract the DMinLine
+ MOV r3, #2
+ ADD r3, r3, r2
+ MOV r2, #1
+ LSL r2, r2, r3 @ Calculate the line size
+
+ SUB r3, r2, #1 @ Calculate the mask
+ BIC r0, r0, r3 @ Align to cache line boundary
+ TST r3, r14
+ BIC r14, r14, r3
+ MCRNE p15, #0, r14, c7, c10, #1 @ Clean D/Unified to PoC by MVA
+
+cleanloop:
+ MCR p15, #0, r0 , c7, c10, #1 @ Clean D/Unified to PoC by MVA
+ ADDS r0, r0, r2 @ Go to next line
+ CMP r0, r14
+ BLT cleanloop
+
+ POP {r14}
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API cleans and invalidates the D-cache/Unified lines corresponding to
+@ the buffer pointer upto the specified length to PoC.
+@ r0 - Start Address
+@ r1 - Number of bytes to be cleaned and flushed
+@*****************************************************************************
+CP15DCacheCleanFlushBuff:
+ PUSH {r14}
+ ADD r14, r0, r1 @ Calculate the end address
+ DMB
+ MRC p15, #0, r2, c0, c0, #1 @ Read Cache Type Register
+ UBFX r2, r2, #16, #4 @ Extract the DMinLine
+ MOV r3, #2
+ ADD r3, r3, r2
+ MOV r2, #1
+ LSL r2, r2, r3 @ Calculate the line size
+
+ SUB r3, r2, #1 @ Calculate the mask
+ BIC r0, r0, r3 @ Align to cache line boundary
+ TST r3, r14
+ BIC r14, r14, r3
+ MCRNE p15, #0, r14, c7, c14, #1 @ Clean and Flush D/U line to PoC
+
+cleanflushloop:
+ MCR p15, #0, r0 , c7, c14, #1 @ Clean and Flush D/U line to PoC
+ ADDS r0, r0, r2 @ Go to next line
+ CMP r0, r14
+ BLT cleanflushloop
+
+ POP {r14}
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API invalidates the D-cache/Unified lines corresponding to
+@ the buffer pointer upto the specified length to PoC.
+@ r0 - Start Address
+@ r1 - Number of bytes to be flushed
+@*****************************************************************************
+CP15DCacheFlushBuff:
+ PUSH {r14}
+ ADD r14, r0, r1 @ Calculate the end address
+ DMB
+ MRC p15, #0, r2, c0, c0, #1 @ Read Cache Type Register
+ UBFX r2, r2, #16, #4 @ Extract the DMinLine
+ MOV r3, #2
+ ADD r3, r3, r2
+ MOV r2, #1
+ LSL r2, r2, r3 @ Calculate the line size
+
+ SUB r3, r2, #1 @ Calculate the mask
+ TST r3, r0
+ BIC r0, r0, r3 @ Align to cache line boundary
+ MCRNE p15, #0, r0, c7, c14, #1 @ Clean and Flush D/U line to PoC
+ ADDNE r0, r0, r2
+ TST r3, r14
+ BIC r14, r14, r3
+ MCRNE p15, #0, r14, c7, c14, #1 @ Clean and Flush D/U line to PoC
+ B dflushcmp
+
+dflushloop:
+ MCR p15, #0, r0 , c7, c6, #1 @ Flush D/U line to PoC
+ ADDS r0, r0, r2 @ Go to next line
+
+dflushcmp:
+ CMP r0, r14
+ BLT dflushloop
+ POP {r14}
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API invlidates I-cache lines from the star address till the length
+@ specified to PoU.
+@ r0 - Start Address
+@ r1 - Number of bytes to be cleaned
+@*****************************************************************************
+CP15ICacheFlushBuff:
+ PUSH {r14}
+ ADD r14, r0, r1 @ Calculate the end address
+ DMB
+ MRC p15, #0, r2, c0, c0, #1 @ Read Cache Type Register
+ UBFX r2, r2, #0, #4 @ Extract the DMinLine
+ MOV r3, #2
+ ADD r3, r3, r2
+ MOV r2, #1
+ LSL r2, r2, r3 @ Calculate the line size
+
+ SUB r3, r2, #1 @ Calculate the mask
+ BIC r0, r0, r3 @ Align to cache line boundary
+ TST r3, r14
+ BIC r14, r14, r3
+ MCRNE p15, #0, r14, c7, c5, #1 @ Invalidate by MVA to PoU
+
+iflushloop:
+ MCR p15, #0, r0, c7, c5, #1 @ Invalidate by MVA to PoU
+ ADDS r0, r0, r2 @ Go to next line
+ CMP r0, r14
+ BLT iflushloop
+
+ POP {r14}
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ Sets TTB0 Register
+@ r0 - Translation Table Base Address
+@*****************************************************************************
+CP15Ttb0Set:
+ MCR p15, #0, r0, c2, c0, #0
+ DMB
+ BX lr
+
+@*****************************************************************************
+@ This API Invalidates the TLB
+@*****************************************************************************
+CP15TlbInvalidate:
+ MCR p15, #0, r0, c8, c7, #0 @ r0 value will be ignored
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API Disables MMU.
+@*****************************************************************************
+CP15MMUDisable:
+ MCR p15, #0, r0, c8, c7, #0 @ Invalidate TLB
+ MRC p15, #0, r0, c1, c0, #0
+ BIC r0, r0, #1
+ MCR p15, #0, r0, c1, c0, #0 @ Clear MMU bit
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API Enables MMU.
+@*****************************************************************************
+CP15MMUEnable:
+ MRC p15, #0, r0, c1, c0, #0
+ ORR r0, r0, #0x001
+ MCR p15, #0, r0, c1, c0, #0 @ Set MMU Enable bit
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API sets the interrupt vector table base address
+@ r0 - Interrput Vector Base Address
+@*****************************************************************************
+CP15VectorBaseAddrSet:
+ MCR p15, #0, r0, c12, c0, #0
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API invalidates the branch predictor
+@*****************************************************************************
+CP15BranchPredictorInvalidate:
+ MCR p15, #0, r0, c7, c5, #6
+ ISB
+ BX lr
+
+@*****************************************************************************
+@ This API enables the branch predictor
+@*****************************************************************************
+CP15BranchPredictionEnable:
+ MRC p15, #0, r0, c1, c0, #0
+ ORR r0, r0, #0x00000800
+ MCR p15, #0, r0, c1, c0, #0
+ BX lr
+
+@*****************************************************************************
+@ This API disables the branch predictor
+@*****************************************************************************
+CP15BranchPredictionDisable:
+ MRC p15, #0, r0, c1, c0, #0
+ BIC r0, r0, #0x00000800
+ MCR p15, #0, r0, c1, c0, #0
+ BX lr
+
+@*****************************************************************************
+@ This API sets the domain access to 'client'
+@*****************************************************************************
+CP15DomainAccessClientSet:
+ LDR r0, _CLIENTD
+ MCR p15, #0, r0, c3, c0, #0
+ DSB
+ BX lr
+
+
+@*****************************************************************************
+@ This API Disables specified features in CP15 control register
+@ r0 - features Features to disable in Coprocessor 15 control
+@ register.
+@ 'features' can take any OR a combination of the
+@ below values.
+@ CP15_CONTROL_TEXREMAP - TEX remap flag
+@ CP15_CONTROL_ACCESSFLAG - Access flag Control
+@ CP15_CONTROL_ALIGN_CHCK - Alignment Fault Checking
+@ CP15_CONTROL_MMU - To enable MMU
+@
+@ Note: Other fields of the CP15 c1 control register are not given here
+@ as they are not of importance for StarterWare. However, optionally
+@ they can also be ADDed.
+@
+@*****************************************************************************
+CP15ControlFeatureDisable:
+ MRC p15, #0, r1, c1, c0, #0
+ BIC r0, r1, r0
+ MCR p15, #0, r0, c1, c0, #0
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API Enables specified features in CP15 control register
+@ r0 - features Features to disable in Coprocessor 15 control
+@ register.
+@ 'features' can take any OR a combination of the
+@ below values.
+@ CP15_CONTROL_TEXREMAP - TEX remap flag
+@ CP15_CONTROL_ACCESSFLAG - Access flag Control
+@ CP15_CONTROL_ALIGN_CHCK - Alignment Fault Checking
+@ CP15_CONTROL_MMU - To enable MMU
+@
+@ Note: Other fields of the CP15 c1 control register are not given here
+@ as they are not of importance for StarterWare. However, optionally
+@ they can also be ADDed.
+@
+@*****************************************************************************
+CP15ControlFeatureEnable:
+ MRC p15, #0, r1, c1, c0, #0
+ ORR r0, r1, r0
+ MCR p15, #0, r0, c1, c0, #0
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API Configures the TTB control register to use only TTB0
+@*****************************************************************************
+CP15TtbCtlTtb0Config:
+ MOV r0, #0x0
+ MCR p15, #0, r0, c2, c0, #2
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API Sets the specified fields in Auxiliary Control Register
+@ r0 - Bit Mask for the bits to be set in Auxiliary Control Register
+@*****************************************************************************
+CP15AuxControlFeatureEnable:
+ MRC p15, #0, r1, c1, c0, #1
+ ORR r0, r0, r1
+ MCR p15, #0, r0, c1, c0, #1
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API Clears the specified fields in Auxiliary Control Register
+@ r0 - Bit Mask for the bits to be cleared in Auxiliary Control Register
+@*****************************************************************************
+CP15AuxControlFeatureDisable:
+ MRC p15, #0, r1, c1, c0, #1
+ BIC r0, r1, r0
+ MCR p15, #0, r0, c1, c0, #1
+ DSB
+ BX lr
+
+@*****************************************************************************
+@ This API returns the main ID register in r0
+@*****************************************************************************
+CP15MainIdPrimPartNumGet:
+ MRC p15, #0, r0, c0, c0, #0
+ UBFX r0, r0, #4, #12
+ BX lr
+
+_CLIENTD:
+ .word 0x55555555
+_FLD_MAX_WAY:
+ .word 0x3ff
+_FLD_MAX_IDX:
+ .word 0x7ff
+
+@
+@ End of the file
+@
+ .end
+
diff --git a/cpsw/src/netif/cpsw.c b/cpsw/src/netif/cpsw.c
new file mode 100755
index 0000000..e82595b
--- /dev/null
+++ b/cpsw/src/netif/cpsw.c
@@ -0,0 +1,1545 @@
+/**
+ * \file cpsw.c
+ *
+ * \brief CPSW device abstraction layer APIs.
+ *
+ * This file contains the device abstraction layer APIs for CPSW RGMII.
+ */
+
+/*
+* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+*/
+/*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include "hw_types.h"
+#include "cpsw.h"
+
+/*******************************************************************************
+* INTERNAL MACRO DEFINITIONS
+*******************************************************************************/
+#define CPSW_CORE_OFFSET (0x10u)
+#define CPSW_MAX_HEADER_DESC (0x08u)
+#define CPDMA_P0_DEF_TX_MAP (0x76543210u)
+#define ALE_ENTRY_WORDS (0x03u)
+#define CPDMA_ERR_CHANNEL_POS (0xFFu)
+#define CPSW_PORT_DUAL_MAC_MODE (0x01u << \
+ CPSW_PORT_P0_TX_IN_CTL_TX_IN_SEL_SHIFT)
+#define CPSW_PORT_RATE_LIM_MODE (0x02u << \
+ CPSW_PORT_P0_TX_IN_CTL_TX_IN_SEL_SHIFT)
+
+/*******************************************************************************
+* API FUNCTION DEFINITIONS
+*******************************************************************************/
+/**
+ * \brief Resets the CPSW Subsystem.
+ *
+ * \param baseAddr Base address of the CPSW Subsystem
+ *
+ * \return None
+ **/
+void CPSWSSReset(unsigned int baseAddr)
+{
+ /* Reset the CPSW */
+ HWREG(baseAddr + CPSW_SS_SOFT_RESET) = CPSW_SS_SOFT_RESET_SOFT_RESET;
+
+ while(HWREG(baseAddr + CPSW_SS_SOFT_RESET)
+ & CPSW_SS_SOFT_RESET_SOFT_RESET);
+}
+
+/**
+ * \brief Force the CPGMAC_SL into gigabit mode if the input GMII_MTCLK has
+ * been stopped by the PHY
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWSlGigModeForceEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) |= CPSW_SL_MACCONTROL_GIG_FORCE;
+}
+
+/**
+ * \brief Enables the fullduplex and gigabit mode to be selected
+ * from the FULLDUPLEX_IN and GIG_IN input signals and not from the
+ * fullduplex and gig bits in this register. The FULLDUPLEX_MODE bit
+ * reflects the actual fullduplex mode selected
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWSlControlExtEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) |= CPSW_SL_MACCONTROL_EXT_EN;
+}
+
+
+/**
+ * \brief Disables the CPGMAC_SL gigabit mode if the input GMII_MTCLK has
+ * been stopped by the PHY
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWSlGigModeForceDisable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) &= ~CPSW_SL_MACCONTROL_GIG_FORCE;
+}
+
+/**
+ * \brief Sets the Transfer mode, 10/100 or gigabit mode and the duplex
+ * mode for the sliver.
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ * \param mode The transfer mode
+ * 'mode' can take one of the below values. \n
+ * CPSW_SLIVER_NON_GIG_HALF_DUPLEX - 10/100 Mbps mode, half duplex. \n
+ * CPSW_SLIVER_NON_GIG_FULL_DUPLEX - 10/100 Mbps mode, full duplex. \n
+ * CPSW_SLIVER_GIG_FULL_DUPLEX - 1000 Mbps mode, full duplex. \n
+ * Note: for 10Mbps mode, CPSW_SLIVER_INBAND has to be configured. \n
+ *
+ * \return None
+ *
+ **/
+void CPSWSlTransferModeSet(unsigned int baseAddr, unsigned int mode)
+{
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) &= ~(CPSW_SL_MACCONTROL_GIG
+ | CPSW_SL_MACCONTROL_FULLDUPLEX);
+
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) |= mode;
+}
+
+/**
+ * \brief Returns the MAC Status. The value will be the contents of the MAC
+ * status register.
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ * \param statFlag Status flags to be read.
+ * statFlag can take an OR combination of the below values. \n
+ * CPSW_SLIVER_STATE - The Sliver state. \n
+ * CPSW_SLIVER_EXT_GIG_INPUT_BIT - The EXT_GIG input bit mask.\n
+ * CPSW_SLIVER_EXT_FULL_DUPLEX_BIT - The EXT_FULLDUPLEX input
+ * bit mask. \n
+ * CPSW_SLIVER_RX_FLOWCTRL - The receive flow control active. \n
+ * CPSW_SLIVER_TX_FLOWCTRL - The transmit flow control.
+ *
+ *
+ * \return MAC Status
+ * The MAC status register value returned can be compared against
+ * the below tokens. \n
+ * CPSW_SLIVER_STATE_IDLE - The Sliver is in idle state. \n
+ * CPSW_SLIVER_EXT_GIG_INPUT_HIGH - The EXT_GIG input
+ * bit is in HIGH state.\n
+ * CPSW_SLIVER_EXT_FULL_DUPLEX_HIGH - The EXT_FULLDUPLEX input
+ * bit is in HIGH state. \n
+ * CPSW_SLIVER_RX_FLOWCTRL_ACTIVE - The receive flow control is
+ * active. \n
+ * CPSW_SLIVER_TX_FLOWCTRL_ACTIVE - The pause time period is
+ * observed for a received
+ * pause frame
+ *
+ **/
+unsigned int CPSWSlMACStatusGet(unsigned int baseAddr, unsigned int statFlag)
+{
+ /* Return the required status only */
+ return (HWREG(baseAddr + CPSW_SL_MACSTATUS) & statFlag);
+}
+
+/**
+ * \brief Resets the CPSW Sliver Logic.
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWSlReset(unsigned int baseAddr)
+{
+ /* Reset the sliver logic */
+ HWREG(baseAddr + CPSW_SL_SOFT_RESET) = CPSW_SL_SOFT_RESET_SOFT_RESET;
+
+ /* Wait till the reset completes */
+ while(CPSW_SL_SOFT_RESET_SOFT_RESET ==
+ ((HWREG(baseAddr + CPSW_SL_SOFT_RESET))
+ & CPSW_SL_SOFT_RESET_SOFT_RESET));
+}
+
+
+/**
+ * \brief Sets the maximum length for received frame.
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ * \param rxMaxLen Maximum length for a received frame
+ * The default value for 'rxMaxLen' is 1518. The maximum value
+ * which can be set is 16383.
+ *
+ * \return None
+ *
+ **/
+void CPSWSlRxMaxLenSet(unsigned int baseAddr, unsigned int rxMaxLen)
+{
+ /* Set the desired maximum length */
+ HWREG(baseAddr + CPSW_SL_RX_MAXLEN) = rxMaxLen;
+}
+
+/**
+ * \brief Enables GMII for the sliver.
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ *
+ * \return None
+ **/
+void CPSWSlGMIIEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) |= CPSW_SL_MACCONTROL_GMII_EN;
+}
+
+/**
+ * \brief Enables RGMII for the sliver.
+ *
+ * \param baseAddr Base address of the CPSW Sliver Module registers.
+ *
+ * \return None
+ **/
+void CPSWSlRGMIIEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SL_MACCONTROL) |= (CPSW_SL_MACCONTROL_GMII_EN
+ | CPSW_SL_MACCONTROL_IFCTL_A
+ | CPSW_SL_MACCONTROL_IFCTL_B);
+}
+
+/**
+ * \brief Resets the CPSW Wrapper module.
+ *
+ * \param baseAddr Base address of the CPSW Wrapper Module
+ *
+ * \return None
+ **/
+void CPSWWrReset(unsigned int baseAddr)
+{
+ /* Reset the CPSW Wrapper */
+ HWREG(baseAddr + CPSW_WR_SOFT_RESET) = CPSW_WR_SOFT_RESET_SOFT_RESET;
+
+ while(HWREG(baseAddr + CPSW_WR_SOFT_RESET)
+ & CPSW_WR_SOFT_RESET_SOFT_RESET);
+}
+
+/**
+ * \brief Resets the Control Register of CPSW Wrapper module
+ *
+ * \param baseAddr Base address of the CPSW Wrapper Module
+ *
+ * \return None
+ **/
+void CPSWWrControlRegReset(unsigned int baseAddr)
+{
+ /* Reset the CPSW Wrapper control Register */
+ HWREG(baseAddr + CPSW_WR_CONTROL) = CPSW_WR_CONTROL_MMR_RESET;
+}
+
+/**
+ * \brief Enables an interrupt for the specified core.
+ *
+ * \param baseAddr Base address of the CPSW Wrapper Module
+ * \param core Core number
+ * \param channel Channel number
+ * \param intFlag Interrupt to be enabled
+ * 'intFlag' can take one of the below values. \n
+ * CPSW_CORE_INT_RX_THRESH - RX threshold interrupt \n
+ * CPSW_CORE_INT_RX_PULSE - RX pulse interrupt \n
+ * CPSW_CORE_INT_TX_PULSE - TX pulse interrupt \n
+ * CPSW_CORE_INT_MISC - Miscellaneous interrupt
+ *
+ * \return None
+ **/
+void CPSWWrCoreIntEnable(unsigned int baseAddr, unsigned int core,
+ unsigned int channel, unsigned int intFlag)
+{
+ HWREG(baseAddr + CPSW_WR_C_RX_THRESH_EN(core) + intFlag) |= (1 << channel);
+}
+
+/**
+ * \brief Disables an interrupt for the specified core.
+ *
+ * \param baseAddr Base address of thei CPSW Wrapper Module
+ * \param core Core number
+ * \param channel Channel number
+ * \param intFlag Interrupt to be disabled
+ * 'intFlag' can take one of the below values. \n
+ * CPSW_CORE_INT_RX_THRESH - RX threshold interrupt \n
+ * CPSW_CORE_INT_RX_PULSE - RX pulse interrupt \n
+ * CPSW_CORE_INT_TX_PULSE - TX pulse interrupt \n
+ * CPSW_CORE_INT_MISC - Miscellaneous interrupt
+ *
+ * \return None
+ **/
+void CPSWWrCoreIntDisable(unsigned int baseAddr, unsigned int core,
+ unsigned int channel, unsigned int intFlag)
+{
+ HWREG(baseAddr + CPSW_WR_C_RX_THRESH_EN(core) + intFlag) &=
+ ~(1 << channel);
+}
+
+/**
+ * \brief Returns the interrupt status of the core for the specified
+ * channel
+ *
+ * \param baseAddr Base address of thei CPSW Wrapper Module
+ * \param core Core number
+ * \param channel Channel number
+ * \param intFlag Interrupt status to be read
+ * 'intFlag' can take one of the below values. \n
+ * CPSW_CORE_INT_RX_THRESH - RX threshold interrupt \n
+ * CPSW_CORE_INT_RX_PULSE - RX pulse interrupt \n
+ * CPSW_CORE_INT_TX_PULSE - TX pulse interrupt \n
+ * CPSW_CORE_INT_MISC - Miscellaneous interrupt
+ *
+ * \return same as intFlag if the status is set
+ * '0' if the status is cleared
+ **/
+unsigned int CPSWWrCoreIntStatusGet(unsigned int baseAddr, unsigned int core,
+ unsigned int channel, unsigned int intFlag)
+{
+ return (HWREG(baseAddr + CPSW_WR_C_RX_THRESH_STAT(core) + intFlag)
+ & (1 << channel));
+}
+
+/**
+ * \brief Returns the RGMII status requested.
+ *
+ * \param baseAddr Base address of the CPSW Wrapper Module
+ * \param statFlag Status to be checked
+ * 'statFlag' can take a combination of the below values. \n
+ * CPSW_RGMII2_DUPLEX - Duplex of RGMII2 \n
+ * CPSW_RGMII2_SPEED - Speed of RGMII2 \n
+ * CPSW_RGMII2_LINK_STAT - Link Status of RGMII2 \n
+ * CPSW_RGMII1_DUPLEX - Duplex of RGMII1 \n
+ * CPSW_RGMII1_SPEED - Speed of RGMII1 \n
+ * CPSW_RGMII1_LINK_STAT - Link Status of RGMII1 \n
+ *
+ * The returned value can be compared agains the below values \n
+ * CPSW_RGMII2_DUPLEX_FULL - RGMII2 full duplex \n
+ * CPSW_RGMII2_DUPLEX_HALF - RGMII2 half duplex \n
+ * CPSW_RGMII2_SPEED_10M - Speed is 10 Mbps \n
+ * CPSW_RGMII2_SPEED_100M - Speed is 100 Mbps \n
+ * CPSW_RGMII2_SPEED_1000M - Speed is 1000 Mbps \n
+ * CPSW_RGMII2_LINK_UP - RGMII2 link is up\n
+ * CPSW_RGMII2_LINK_DOWN - RGMII2 link is down \n
+ * CPSW_RGMII1_DUPLEX_FULL - RGMII1 full duplex \n
+ * CPSW_RGMII1_DUPLEX_HALF - RGMII1 half duplex \n
+ * CPSW_RGMII1_SPEED_10M - Speed is 10 Mbps \n
+ * CPSW_RGMII1_SPEED_100M - Speed is 100 Mbps \n
+ * CPSW_RGMII1_SPEED_1000M - Speed is 1000 Mbps \n
+ * CPSW_RGMII1_LINK_UP - RGMII1 link is up\n
+ * CPSW_RGMII1_LINK_DOWN - RGMII1 link is down \n
+ *
+ * \return Status of RGMII. Return value can be compared agains the same
+ * statFlag passed.
+ **/
+unsigned int CPSWWrRGMIIStatusGet(unsigned int baseAddr, unsigned int statFlag)
+{
+ return (HWREG(baseAddr + CPSW_WR_RGMII_CTL) & statFlag);
+}
+
+/**
+ * \brief Initializes the ALE. The ALE logic is reset and the ALE table
+ * entries are cleared.
+ *
+ * \param baseAddr Base address of the ALE module
+ *
+ * \return None
+ **/
+void CPSWALEInit(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) = (CPSW_ALE_CONTROL_CLEAR_TABLE
+ | CPSW_ALE_CONTROL_ENABLE_ALE);
+}
+
+/**
+ * \brief Age Out Address Table. The Untouched ageable ALE table
+ * entries are cleared.
+ *
+ * \param baseAddr Base address of the ALE module
+ *
+ * \return None
+ **/
+void CPSWALEAgeOut(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) |= CPSW_ALE_CONTROL_AGE_OUT_NOW;
+
+ while(CPSW_ALE_CONTROL_AGE_OUT_NOW & (HWREG(baseAddr + CPSW_ALE_CONTROL)));
+
+}
+
+/**
+ * \brief Sets the Broadcast Packet Rate Limit
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param bplVal The Broadcast Packet Rate Limit Value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEBroadcastRateLimitSet(unsigned int baseAddr, unsigned int portNum,
+ unsigned int bplVal)
+{
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) &=
+ ~CPSW_ALE_PORTCTL0_BCAST_LIMIT;
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) |=
+ (bplVal << CPSW_ALE_PORTCTL0_BCAST_LIMIT_SHIFT);
+}
+
+/**
+ * \brief Sets the Multicast Packet Rate Limit
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param mplVal The Multicast Packet Rate Limit Value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEMulticastRateLimitSet(unsigned int baseAddr, unsigned int portNum,
+ unsigned int mplVal)
+{
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) &=
+ ~CPSW_ALE_PORTCTL0_MCAST_LIMIT;
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) |=
+ (mplVal << CPSW_ALE_PORTCTL0_MCAST_LIMIT_SHIFT);
+}
+
+/**
+ * \brief VLAN ID Ingress Check
+ *
+ * \param baseAddr Base Address of the ALE module
+ *
+ * \return None
+ *
+ **/
+void CPSWALEVIDIngressCheckSet(unsigned int baseAddr, unsigned int portNum)
+{
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) |=
+ CPSW_ALE_PORTCTL0_MCAST_LIMIT;
+}
+
+/**
+ * \brief Sets the port state in the ALE for a given port
+ *
+ * \param baseAddr Base address of the ALE module
+ * \param portNum The port number
+ * \param portState The port state to be set
+ * 'portState' can take one of the below values \n
+ * CPSW_ALE_PORT_STATE_FWD - ALE state is Forward \n
+ * CPSW_ALE_PORT_STATE_LEARN - ALE state is Learn \n
+ * CPSW_ALE_PORT_STATE_BLOCKED - ALE state is Blocked \n
+ * CPSW_ALE_PORT_STATE_DISABLED - ALE state is Disabled
+ *
+ * \return None
+ **/
+void CPSWALEPortStateSet(unsigned int baseAddr, unsigned int portNum,
+ unsigned int portState)
+{
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) &=
+ ~CPSW_ALE_PORTCTL0_PORT_STATE;
+
+ HWREG(baseAddr + CPSW_ALE_PORTCTL(portNum)) |= portState;
+}
+
+/**
+ * \brief Sets VLAN Aware mode for ALE to Flood if VLAN not found
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALEVLANAwareSet(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) |= CPSW_ALE_CONTROL_ALE_VLAN_AWARE;
+}
+
+/**
+ * \brief Clears VLAN Aware mode for ALE to drop packets
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALEVLANAwareClear(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) &= ~CPSW_ALE_CONTROL_ALE_VLAN_AWARE;
+}
+
+/**
+ * \brief Configure Rate Limit to TX Mode
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALERateLimitTXMode(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) |= CPSW_ALE_CONTROL_RATE_LIMIT_TX;
+}
+
+/**
+ * \brief Configure Rate Limit to RX Mode
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALERateLimitRXMode(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) &= ~CPSW_ALE_CONTROL_RATE_LIMIT_TX;
+}
+
+/**
+ * \brief Enable Rate Limit for ALE
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALERateLimitEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) |= CPSW_ALE_CONTROL_ENABLE_RATE_LIMIT;
+}
+
+/**
+ * \brief Disable Rate Limit for ALE
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALERateLimitDisable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) &= ~CPSW_ALE_CONTROL_ENABLE_RATE_LIMIT;
+}
+
+/**
+ * \brief Enable MAC Authorization Mode for ALE
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALEAUTHModeSet(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) |= CPSW_ALE_CONTROL_ENABLE_AUTH_MODE;
+}
+
+/**
+ * \brief Disable MAC Authorization Mode for ALE
+ *
+ * \param baseAddr Base address of the ALE Module
+ *
+ * \return None
+ **/
+void CPSWALEAUTHModeClear(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) &= ~CPSW_ALE_CONTROL_ENABLE_AUTH_MODE;
+}
+
+/**
+ * \brief Sets an ALE table entry
+ *
+ * \param baseAddr Base address of the ALE Module
+ * \param aleTblIdx The Index of the table entry
+ * \param aleEntryPtr The address of the entry to be set
+ *
+ * \return None
+ **/
+void CPSWALETableEntrySet(unsigned int baseAddr, unsigned int aleTblIdx,
+ unsigned int *aleEntryPtr)
+{
+ unsigned int cnt;
+
+ for (cnt = 0; cnt < ALE_ENTRY_WORDS; cnt++)
+ {
+ HWREG(baseAddr + CPSW_ALE_TBLW(cnt)) = *(aleEntryPtr + cnt);
+ }
+
+ HWREG(baseAddr + CPSW_ALE_TBLCTL) =
+ aleTblIdx | CPSW_ALE_TBLCTL_WRITE_RDZ;
+}
+
+/**
+ * \brief Returns an ALE table entry
+ *
+ * \param baseAddr Base address of the ALE Module
+ * \param aleTblIdx The Index of the table entry
+ * \param aleEntryPtr The address where the ALE entry to be written
+ *
+ * \return None
+ **/
+void CPSWALETableEntryGet(unsigned int baseAddr, unsigned int aleTblIdx,
+ unsigned int *aleEntryPtr)
+{
+ unsigned int cnt;
+
+ HWREG(baseAddr + CPSW_ALE_TBLCTL) = aleTblIdx;
+
+ for (cnt = 0; cnt < ALE_ENTRY_WORDS; cnt++)
+ {
+ *(aleEntryPtr + cnt) = HWREG(baseAddr + CPSW_ALE_TBLW(cnt));
+ }
+}
+
+/**
+ * \brief Returns the prescale value for ALE. The input clock is divided
+ * by this value to use in the broadcast/multicast rate limiters.
+ *
+ * \param baseAddr Base Address of the ALE module
+ *
+ * \return Prescale value
+ *
+ **/
+unsigned int CPSWALEPrescaleGet(unsigned int baseAddr)
+{
+ return (HWREG(baseAddr + CPSW_ALE_PRESCALE)
+ & CPSW_ALE_PRESCALE_ALE_PRESCALE);
+}
+
+/**
+ * \brief Sets the prescale value for ALE. The input clock is divided
+ * by this value to use in the broadcast/multicast rate limiters.
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param psVal The prescale value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEPrescaleSet(unsigned int baseAddr, unsigned int psVal)
+{
+ HWREG(baseAddr + CPSW_ALE_PRESCALE) |= psVal
+ & CPSW_ALE_PRESCALE_ALE_PRESCALE ;
+}
+
+/**
+ * \brief Sets the Unknown VLAN Force Untagged Egress
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param ueVal The Unknown VLAN Fornce Untagged Egress value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEUnknownUntaggedEgressSet(unsigned int baseAddr, unsigned int ueVal)
+{
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) &=
+ ~CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_FORCE_UNTA;
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) |=
+ (ueVal << CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_FORCE_UNTA_SHIFT);
+}
+
+/**
+ * \brief Sets the Unknown VLAN Registered Multicast Flood Mask
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param rfmVal Unknown VLAN Registered Multicast Flood Mask Value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEUnknownRegFloodMaskSet(unsigned int baseAddr, unsigned int rfmVal)
+{
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) &=
+ ~CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_MCAST_FLO;
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) |=
+ (rfmVal << CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_MCAST_FLO_SHIFT);
+}
+
+/**
+ * \brief Sets the Unknown VLAN UnRegistered Multicast Flood Mask
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param ufmVal Unknown VLAN UnRegistered Multicast Flood Mask Value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEUnknownUnRegFloodMaskSet(unsigned int baseAddr, unsigned int ufmVal)
+{
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) &=
+ ~CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_REG_MCAST;
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) |=
+ (ufmVal << CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_REG_MCAST_SHIFT);
+}
+
+/**
+ * \brief Sets the Unknown VLAN Member List
+ *
+ * \param baseAddr Base Address of the ALE module
+ * \param mlVal Unknown VLAN UnRegistered Multicast Flood Mask Value
+ *
+ * \return None
+ *
+ **/
+void CPSWALEUnknownMemberListSet(unsigned int baseAddr, unsigned int mlVal)
+{
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) &=
+ ~CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_VLAN_MEM;
+ HWREG(baseAddr + CPSW_ALE_UNKNOWN_VLAN) |=
+ (mlVal << CPSW_ALE_UNKNOWN_VLAN_UNKNOWN_VLAN_MEM_SHIFT);
+}
+
+/**
+ * \brief Enables the bypassing of the ALE logic
+ *
+ * \param baseAddr Base Address of the ALE module
+ *
+ * \return None
+ *
+ **/
+void CPSWALEBypassEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) |= CPSW_ALE_CONTROL_ALE_BYPASS;
+}
+
+/**
+ * \brief Disables the bypassing of the ALE logic
+ *
+ * \param baseAddr Base Address of the ALE module
+ *
+ * \return None
+ *
+ **/
+void CPSWALEBypassDisable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_ALE_CONTROL) &= ~CPSW_ALE_CONTROL_ALE_BYPASS;
+}
+
+/**
+ * \brief Enables the receive flow control for CPSW for a given port
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ * \param portNum The port number
+ *
+ * \return None
+ *
+ **/
+void CPSWRxFlowControlEnable(unsigned int baseAddr, unsigned int portNum)
+{
+ HWREG(baseAddr + CPSW_SS_FLOW_CONTROL) |= (1 << portNum);
+}
+
+/**
+ * \brief Disables the receive flow control for CPSW for a given port
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ * \param portNum The port number
+ *
+ * \return None
+ *
+ **/
+void CPSWRxFlowControlDisable(unsigned int baseAddr, unsigned int portNum)
+{
+ HWREG(baseAddr + CPSW_SS_FLOW_CONTROL) &= ~(1 << portNum);
+}
+
+/**
+ * \brief Enables the software idle mode, causing the switch fabric to stop
+ * forward packets at the next start of packet.
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ *
+ * \return None
+ *
+ **/
+void CPSWSoftwareIdleEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SS_SOFT_IDLE) |= CPSW_SS_SOFT_IDLE_SOFT_IDLE;
+}
+
+/**
+ * \brief Disables the software idle mode, causing the switch fabric to
+ * forward packets at the next start of packet.
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ *
+ * \return None
+ *
+ **/
+void CPSWSoftwareIdleDisable(unsigned int baseAddr, unsigned int portNum)
+{
+ (void) portNum;
+ HWREG(baseAddr + CPSW_SS_SOFT_IDLE) &= ~CPSW_SS_SOFT_IDLE_SOFT_IDLE;
+}
+
+/**
+ * \brief Enables the CPSW statistics for the given port
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ * \param portNum The port number
+ *
+ * \return None
+ *
+ **/
+void CPSWStatisticsEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SS_STAT_PORT_EN) = CPSW_SS_STAT_PORT_EN_P0_STAT_EN
+ | CPSW_SS_STAT_PORT_EN_P1_STAT_EN
+ | CPSW_SS_STAT_PORT_EN_P2_STAT_EN;
+}
+
+/**
+ * \brief Enables the VLAN aware mode for CPSW
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ *
+ * \return None
+ *
+ **/
+void CPSWVLANAwareEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SS_CONTROL) |= CPSW_SS_CONTROL_VLAN_AWARE;
+}
+
+/**
+ * \brief Disables the VLAN aware mode for CPSW
+ *
+ * \param baseAddr Base Address of the CPSW subsystem
+ *
+ * \return None
+ *
+ **/
+void CPSWVLANAwareDisable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_SS_CONTROL) &= ~CPSW_SS_CONTROL_VLAN_AWARE;
+}
+
+/**
+ * \brief Sets the ethernet address at the CPSW port
+ *
+ * \param baseAddr Base address of the CPSW Port Module registers
+ * \param ethAddr Start address of the 6 byte ethernet address
+ *
+ * \return None
+ *
+ **/
+void CPSWPortSrcAddrSet(unsigned int baseAddr, unsigned char *ethAddr)
+{
+
+ HWREG(baseAddr + CPSW_PORT_SA_HI) =
+ ethAddr[0]
+ | (ethAddr[1] << CPSW_PORT_P1_SA_HI_MACSRCADDR_39_32_SHIFT)
+ | (ethAddr[2] << CPSW_PORT_P1_SA_HI_MACSRCADDR_31_24_SHIFT)
+ | (ethAddr[3] << CPSW_PORT_P1_SA_HI_MACSRCADDR_23_16_SHIFT);
+ HWREG(baseAddr + CPSW_PORT_SA_LO) =
+ ethAddr[4]
+ | (ethAddr[5] << CPSW_PORT_P1_SA_LO_MACSRCADDR_7_0_SHIFT);
+}
+
+/**
+ * \brief Sets Dual Mac Mode for CPSW Port0
+ *
+ * \param baseAddr Base address of the CPSW Host Port Module registers
+ *
+ * \return None
+ *
+ **/
+void CPSWHostPortDualMacModeSet(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_PORT_TX_IN_CTL) &= ~CPSW_PORT_P0_TX_IN_CTL_TX_IN_SEL;
+ HWREG(baseAddr + CPSW_PORT_TX_IN_CTL) |=
+ CPSW_PORT_P0_TX_IN_CTL_TX_IN_DUAL_MAC;
+}
+
+/**
+ * \brief Configures Port VLAN
+ *
+ * \param baseAddr Base address of the CPSW Port Module registers
+ * \param vlanId VLAN ID to be set
+ * \param cfiBit CFI value to be set
+ * \param vlanPri Port VLAN priority
+ * 'vlanId' can take a value from 0 to 0xFFF \n
+ * 'cfiBit' can be either 0 or 1. \n
+ * 'vlanPri' can be any value between and including 0 and 7.
+ *
+ * \return None
+ *
+ **/
+void CPSWPortVLANConfig(unsigned int baseAddr, unsigned int vlanId,
+ unsigned int cfiBit, unsigned int vlanPri)
+{
+ HWREG(baseAddr + CPSW_PORT_PORT_VLAN) = vlanId
+ | (cfiBit << CPSW_PORT_P2_PORT_VLAN_PORT_CFI_SHIFT)
+ | (vlanPri << CPSW_PORT_P2_PORT_VLAN_PORT_PRI_SHIFT);
+}
+
+/**
+ * \brief Returns the requested CPSW Statistics
+ *
+ * \param baseAddr Base address of the CPSW Status Module registers.
+ * \param statReg Statistics Register to be read
+ *
+ * \return The requested statistics
+ *
+ **/
+unsigned int CPSWStatisticsGet(unsigned int baseAddr, unsigned int statReg)
+{
+ return (HWREG(baseAddr + statReg));
+}
+
+/**
+ * \brief Resets the CPDMA
+ *
+ * \param baseAddr Base address of the CPDMA Module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMAReset(unsigned int baseAddr)
+{
+ unsigned int cnt;
+
+ /* Reset the CPDMA */
+ HWREG(baseAddr + CPSW_CPDMA_CPDMA_SOFT_RESET) =
+ CPSW_CPDMA_CPDMA_SOFT_RESET_SOFT_RESET;
+
+ /* Wait till the reset completes */
+ while(HWREG(baseAddr + CPSW_CPDMA_CPDMA_SOFT_RESET)
+ & CPSW_CPDMA_CPDMA_SOFT_RESET_SOFT_RESET);
+
+ /* Initialize all the header descriptor pointer registers */
+ for(cnt = 0; cnt< CPSW_MAX_HEADER_DESC; cnt++)
+ {
+ HWREG(baseAddr + CPSW_CPDMA_TX_HDP(cnt)) = 0;
+ HWREG(baseAddr + CPSW_CPDMA_RX_HDP(cnt)) = 0;
+ HWREG(baseAddr + CPSW_CPDMA_TX_CP(cnt)) = 0;
+ HWREG(baseAddr + CPSW_CPDMA_RX_CP(cnt)) = 0;
+ }
+}
+
+/**
+ * \brief Enables the TXPULSE Interrupt Generation.
+ *
+ * \param baseAddr Base address of the CPDMA Module registers.
+ * \param channel Channel number for which interrupt to be enabled
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMATxIntEnable(unsigned int baseAddr, unsigned int channel)
+{
+ HWREG(baseAddr + CPSW_CPDMA_TX_INTMASK_SET) |= (1 << channel);
+}
+
+/**
+ * \brief Enables the RXPULSE Interrupt Generation.
+ *
+ * \param baseAddr Base address of the CPDMA Module registers.
+ * \param channel Channel number for which interrupt to be enabled
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMARxIntEnable(unsigned int baseAddr, unsigned int channel)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_INTMASK_SET) |= (1 << channel);
+}
+
+/**
+ * \brief Disables the TXPULSE Interrupt Generation.
+ *
+ * \param baseAddr Base address of the CPDMA Module registers.
+ * \param channel Channel number for which interrupt to be disabled
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMATxIntDisable(unsigned int baseAddr, unsigned int channel)
+{
+ HWREG(baseAddr + CPSW_CPDMA_TX_INTMASK_CLEAR) |= (1 << channel);
+
+}
+
+/**
+ * \brief Disables the RXPULSE Interrupt Generation.
+ *
+ * \param baseAddr Base address of the CPDMA Module registers.
+ * \param channel Channel number for which interrupt to be disabled
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMARxIntDisable(unsigned int baseAddr, unsigned int channel)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_INTMASK_CLEAR) |= (1 << channel);
+
+}
+
+/**
+ * \brief API to enable the transmit in the TX Control Register.
+ * After the transmit is enabled, any write to TXHDP of
+ * a channel will start transmission
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMATxEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_CPDMA_TX_CONTROL) = CPSW_CPDMA_TX_CONTROL_TX_EN;
+}
+
+/**
+ * \brief API to enable the receive in the RX Control Register.
+ * After the receive is enabled, and write to RXHDP of
+ * a channel, the data can be received in the destination
+ * specified by the corresponding RX buffer descriptor.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMARxEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_CONTROL) = CPSW_CPDMA_RX_CONTROL_RX_EN;
+}
+
+/**
+ * \brief API to write the TX HDP register. If transmit is enabled,
+ * write to the TX HDP will immediately start transmission.
+ * The data will be taken from the buffer pointer of the TX buffer
+ * descriptor written to the TX HDP
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param descHdr Address of the TX buffer descriptor
+ * \param channel Channel Number
+ *
+ * \return None
+ *
+ **/
+#include <bsp.h>
+void CPSWCPDMATxHdrDescPtrWrite(unsigned int baseAddr, unsigned int descHdr,
+ unsigned int channel)
+{
+ HWREG(baseAddr + CPSW_CPDMA_TX_HDP(channel)) = descHdr;
+}
+
+/**
+ * \brief API to write the RX HDP register. If receive is enabled,
+ * write to the RX HDP will enable data reception to point to
+ * the corresponding RX buffer descriptor's buffer pointer.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param descHdr Address of the RX buffer descriptor
+ * \param channel Channel Number
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMARxHdrDescPtrWrite(unsigned int baseAddr, unsigned int descHdr,
+ unsigned int channel)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_HDP(channel)) = descHdr;
+}
+
+/**
+ * \brief Writes the DMA End Of Interrupt Vector.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param eoiFlag Type of interrupt to acknowledge to the CPDMA
+ * 'eoiFlag' can take the following values \n
+ * CPSW_EOI_TX_PULSE - TX Pulse Interrupt \n
+ * CPSW_EOI_RX_PULSE - RX Pulse Interrupt \n
+ * CPSW_EOI_RX_THRESH_PULSE - RX Pulse Threshold Interrupt \n
+ * CPSW_EOI_MISC_PULSE - Misc Interrupt \n
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMAEndOfIntVectorWrite(unsigned int baseAddr, unsigned int eoiFlag)
+{
+ /* Acknowledge the CPDMA */
+ HWREG(baseAddr + CPSW_CPDMA_CPDMA_EOI_VECTOR) = eoiFlag;
+}
+
+/**
+ * \brief Reads the RX Completion Pointer for a specific channel
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param channel Channel Number.
+ *
+ * \return RX Completion Pointer value.
+ *
+ **/
+unsigned int CPSWCPDMATxCPRead(unsigned int baseAddr, unsigned int channel)
+{
+ return HWREG(baseAddr + CPSW_CPDMA_TX_CP(channel));
+}
+
+/**
+ * \brief Writes the the TX Completion Pointer for a specific channel
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param channel Channel Number.
+ * \param comPtr Completion Pointer Value to be written
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMATxCPWrite(unsigned int baseAddr, unsigned int channel,
+ unsigned int comPtr)
+{
+ HWREG(baseAddr + CPSW_CPDMA_TX_CP(channel)) = comPtr;
+}
+
+/**
+ * \brief Reads the RX Completion Pointer for a specific channel
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param channel Channel Number.
+ *
+ * \return RX Completion Pointer value.
+ *
+ **/
+unsigned int CPSWCPDMARxCPRead(unsigned int baseAddr, unsigned int channel)
+{
+ return HWREG(baseAddr + CPSW_CPDMA_RX_CP(channel));
+}
+
+/**
+ * \brief Writes the the RX Completion Pointer for a specific channel
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param channel Channel Number.
+ * \param comPtr Completion Pointer Value to be written
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMARxCPWrite(unsigned int baseAddr, unsigned int channel,
+ unsigned int comPtr)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_CP(channel)) = comPtr;
+}
+
+/**
+ * \brief Set the free buffers for a specific channel
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param channel Channel Number.
+ * \param nBuf Number of free buffers
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMANumFreeBufSet(unsigned int baseAddr, unsigned int channel,
+ unsigned int nBuf)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_FREEBUFFER(channel)) = nBuf;
+}
+
+/**
+ * \brief Returns the CPDMA Status.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers.
+ * \param statFlag The status flags to be read
+ * 'statFlag' can take one of the following values \n
+ * CPDMA_STAT_IDLE - to check if CPDMA is idle. \n
+ * CPDMA_STAT_TX_HOST_ERR_CODE - TX host error code. \n
+ * CPDMA_STAT_TX_HOST_ERR_CHAN - TX host error channel. \n
+ * CPDMA_STAT_RX_HOST_ERR_CODE - RX host error code. \n
+ * CPDMA_STAT_RX_HOST_ERR_CHAN - RX host error channel. \n
+ *
+ * \return the DMA status for the status flag passed.
+ * The return values for CPDMA_STAT_IDLE are, \n
+ * CPDMA_STAT_IDLE - CPDMA is in idle state \n
+ * CPDMA_STAT_NOT_IDLE - CPDMA is not in idle state \n
+ *
+ * The return values for CPDMA_STAT_TX_HOST_ERR_CODE are, \n
+ * CPDMA_STAT_TX_NO_ERR - No error \n
+ * CPDMA_STAT_TX_SOP_ERR - SOP error \n
+ * CPDMA_STAT_TX_OWN_ERR - Ownership bit not
+ * set in SOP buffer \n
+ * CPDMA_STAT_TX_ZERO_DESC - Zero Next Buffer
+ * Descriptor Pointer Without EOP \n
+ * CPDMA_STAT_TX_ZERO_BUF_PTR - Zero Buffer Pointer \n
+ * CPDMA_STAT_TX_ZERO_BUF_LEN - Zero Buffer Length \n
+ * CPDMA_STAT_TX_PKT_LEN_ERR - Packet Length Error \n
+ *
+ * The return values for CPDMA_STAT_RX_HOST_ERR_CODE are, \n
+ * CPDMA_STAT_RXi_NO_ERR - No error \n
+ * CPDMA_STAT_RX_OWN_NOT_SET - Ownership bit not set in
+ input buffer \n
+ * CPDMA_STAT_RX_ZERO_BUF_PTR - Zero Buffer Pointer\n
+ * CPDMA_STAT_RX_ZERO_BUF_LEN - Zero Buffer Length on
+ * non-SOP descriptor \n
+ * CPDMA_STAT_RX_SOP_BUF_LEN_ERR - SOP buffer length not
+ * greater than offset\n
+ *
+ **/
+unsigned int CPSWCPDMAStatusGet(unsigned int baseAddr, unsigned int statFlag)
+{
+ return (((HWREG(baseAddr + CPSW_CPDMA_DMASTATUS)) & statFlag)
+ >> (statFlag & CPDMA_ERR_CHANNEL_POS));
+}
+
+/**
+ * \brief Configures the CPDMA module by writing the configuration value
+ * to the DMA control register.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ * \param cfg CPDMA configuration written to control register
+ * 'cfg' shall be CPDMA_CFG(tx_rlim, rx_cef, cmd_idle,
+ * rx_offlen_blk, rx_own, tx_ptype). \n
+ * The parameter 'tx_rlim' to CPDMA_CFG can take one of the below
+ * values, showing which all channels are rate-limited. \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_6 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_5 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_4 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_3 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_2 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_1 \n
+ * CPDMA_CFG_TX_RATE_LIM_CH_7_TO_0 \n
+ * The parameter 'rx_cef' to CPDMA_CFG can take one of the below
+ * values \n
+ * CPDMA_CFG_COPY_ERR_FRAMES - To copy error frames to memory \n
+ * CPDMA_CFG_NO_COPY_ERR_FRAMES - Not to copy error frames \n
+ * The parameter 'cmd_idle' to CPDMA_CFG can take one of the below
+ * values \n
+ * CPDMA_CFG_IDLE_COMMAND - Idle commanded \n
+ * CPDMA_CFG_IDLE_COMMAND_NONE - Idle not commanded \n
+ * The parameter 'rx_offlen_blk' to CPDMA_CFG can take one of the below
+ * values \n
+ * CPDMA_CFG_BLOCK_RX_OFF_LEN_WRITE - Block the DMA writes to the
+ * offset/length field during
+ * packet processing. \n
+ * CPDMA_CFG_NOT_BLOCK_RX_OFF_LEN_WRITE - Do not Block the DMA writes
+ * to the offset/length field during
+ * packet processing. \n
+ * The parameter 'rx_own' to CPDMA_CFG can take one of the below
+ * values \n
+ * CPDMA_CFG_RX_OWN_1 - The CPDMA writes 1 to the ownership bit at
+ * the end of packet processing. \n
+ * CPDMA_CFG_RX_OWN_0 - The CPDMA writes 0 to the ownership bit at
+ * the end of packet processing. \n
+ * The parameter 'tx_ptype' to CPDMA_CFG can take one of the below
+ * values \n
+ * CPDMA_CFG_TX_PRI_ROUND_ROBIN - The next channel for transmit is
+ * chosen round-robin. \n
+ * CPDMA_CFG_TX_PRI_FIXED - The next channel for transmit is
+ * chosen priority based, channel 7 with the
+ * highest priority \n
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMAConfig(unsigned int baseAddr, unsigned int cfg)
+{
+ HWREG(baseAddr + CPSW_CPDMA_DMACONTROL) = cfg;
+}
+
+/**
+ * \brief Enable the command idle mode for CPDMA. When this API is called, the
+ * CPSW stops all the reception and transmission. However, if receiving
+ * the current frame will be received completely before going to the idle
+ * state. Also, while transmitting, the contents in the fifo will be sent
+ * fully.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMACmdIdleEnable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_CPDMA_DMACONTROL) |= CPSW_CPDMA_DMACONTROL_CMD_IDLE;
+
+ /* Wait till the state changes to idle */
+ while((HWREG(baseAddr + CPSW_CPDMA_DMASTATUS) & CPSW_CPDMA_DMASTATUS_IDLE)
+ != CPSW_CPDMA_DMASTATUS_IDLE);
+}
+
+/**
+ * \brief Disable the command idle mode for CPDMA.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMACmdIdleDisable(unsigned int baseAddr)
+{
+ HWREG(baseAddr + CPSW_CPDMA_DMACONTROL) &= ~CPSW_CPDMA_DMACONTROL_CMD_IDLE;
+}
+
+/**
+ * \brief Sets the RX buffer offset value. The RX buffer offset will be
+ * written by the port into each frame SOP buffer descriptor
+ * buffer_offset field. The frame data will begin after the
+ * rx_buffer_offset value of bytes. This value will be used for
+ * all the channels .
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ * \param bufOff Buffer offset value
+ *
+ * \return None
+ *
+ **/
+void CPSWCPDMARxBufOffsetSet(unsigned int baseAddr, unsigned int bufOff)
+{
+ HWREG(baseAddr + CPSW_CPDMA_RX_BUFFER_OFFSET) = bufOff;
+}
+
+/**
+ * \brief Returns the raw transmit interrupt pending status.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ * \param chanMask Channel Mask
+ * 'chanMask' can be given for one or more channels. \n
+ * 0x01- for 0th channel, 0x80 for 7th channel, 0x81 for both 0th
+ * and 7th channel etc. \n
+ *
+ * \return Raw receive interrupt status \n
+ * bits for the 'chanMask' will be set if interrupt is pending \n
+ * bits for the 'chanMask' will be clear if interrupt is not
+ * pending \n
+ *
+ **/
+unsigned int CPSWCPDMATxIntStatRawGet(unsigned int baseAddr,
+ unsigned int chanMask)
+{
+ return (HWREG(baseAddr + CPSW_CPDMA_TX_INTSTAT_RAW) & chanMask);
+}
+
+/**
+ * \brief Returns the masked transmit interrupt pending status.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ * \param chanMask Channel Mask
+ * 'chanMask' can be given for one or more channels. \n
+ * 0x01- for 0th channel, 0x80 for 7th channel, 0x81 for both 0th
+ * and 7th channel etc. \n
+ *
+ * \return Masked transmit interrupt status \n
+ * bits for the 'chanMask' will be set if interrupt is pending \n
+ * bits for the 'chanMask' will be cleared if interrupt is not
+ * pending \n
+ *
+ **/
+unsigned int CPSWCPDMATxIntStatMaskedGet(unsigned int baseAddr,
+ unsigned int chanMask)
+{
+ return (HWREG(baseAddr + CPSW_CPDMA_TX_INTSTAT_MASKED) & chanMask);
+}
+
+/**
+ * \brief Returns the raw receive interrupt pending status.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ * \param chanMask Channel Mask
+ * \param intType Interrupt type
+ * 'chanMask' can be given for one or more channels. \n
+ * 0x01- for 0th channel, 0x80 for 7th channel, 0x81 for both 0th
+ * and 7th channel etc. \n
+ * 'intType' can take one of the following values. \n
+ * CPDMA_RX_INT_THRESH_PEND - RX threshold interrupt pending \n
+ * CPDMA_RX_INT_PULSE_PEND - RX pulse interrupt pending \n
+ *
+ * \return Raw receive interrupt status \n
+ * bits for the 'chanMask' will be set if interrupt is pending \n
+ * bits for the 'chanMask' will be cleared if interrupt is not
+ * pending \n
+ *
+ **/
+unsigned int CPSWCPDMARxIntStatRawGet(unsigned int baseAddr,
+ unsigned int chanMask,
+ unsigned int intType)
+{
+ return ((HWREG(baseAddr + CPSW_CPDMA_RX_INTSTAT_RAW) >> intType)
+ & chanMask);
+}
+
+/**
+ * \brief Returns the masked receive interrupt pending status.
+ *
+ * \param baseAddr Base Address of the CPDMA module registers
+ * \param chanMask Channel Mask
+ * \param intType Interrupt type
+ * 'chanMask' can be given for one or more channels. \n
+ * 0x01- for 0th channel, 0x80 for 7th channel, 0x81 for both 0th
+ * and 7th channel etc. \n
+ * 'intType' can take one of the following values. \n
+ * CPDMA_RX_INT_THRESH_PEND - RX threshold interrupt pending \n
+ * CPDMA_RX_INT_PULSE_PEND - RX pulse interrupt pending \n
+ *
+ * \return Masked receive interrupt status \n
+ * bits for the 'chanMask' will be set if interrupt is pending \n
+ * bits for the 'chanMask' will be cleared if interrupt is not
+ * pending \n
+ *
+ **/
+unsigned int CPSWCPDMARxIntStatMaskedGet(unsigned int baseAddr,
+ unsigned int chanMask,
+ unsigned int intType)
+{
+ return ((HWREG(baseAddr + CPSW_CPDMA_RX_INTSTAT_MASKED) >> intType)
+ & chanMask);
+}
+
+/**
+ * \brief Saves the CPSW register context. This can be used while going
+ * to power down mode where CPSW power will be cut down.
+ *
+ * \param contextPtr Pointer to the structure where CPSW register context
+ * need to be saved.
+ *
+ * \return None
+ *
+ **/
+void CPSWContextSave(CPSWCONTEXT *contextPtr)
+{
+ unsigned int idx;
+ unsigned int *cppiDest = (unsigned int*)contextPtr->cppiRamBase;
+
+ CPSWCPDMACmdIdleEnable(contextPtr->cpdmaBase);
+
+ /* Restore the CPPI RAM contents */
+ for(idx = 0; idx < (CPSW_SIZE_CPPI_RAM / 4); idx++, cppiDest++)
+ {
+ contextPtr->cppiRam[idx] = *cppiDest;
+ }
+
+ contextPtr->aleCtrl = HWREG(contextPtr->aleBase + CPSW_ALE_CONTROL);
+ contextPtr->alePortCtl[0] = HWREG(contextPtr->aleBase + CPSW_ALE_PORTCTL(0));
+ contextPtr->alePortCtl[1] = HWREG(contextPtr->aleBase + CPSW_ALE_PORTCTL(1));
+ contextPtr->alePortCtl[2] = HWREG(contextPtr->aleBase + CPSW_ALE_PORTCTL(2));
+
+ for(idx = 0; idx < CPSW_MAX_NUM_ALE_ENTRY; idx++)
+ {
+ CPSWALETableEntryGet(contextPtr->aleBase, idx,
+ &(contextPtr->aleEntry[idx * 3]));
+ }
+
+ contextPtr->ssStatPortEn = HWREG(contextPtr->ssBase + CPSW_SS_STAT_PORT_EN);
+ contextPtr->port1SaHi = HWREG(contextPtr->port1Base + CPSW_PORT_SA_HI);
+ contextPtr->port1SaLo = HWREG(contextPtr->port1Base + CPSW_PORT_SA_LO);
+ contextPtr->port2SaHi = HWREG(contextPtr->port2Base + CPSW_PORT_SA_HI);
+ contextPtr->port2SaLo = HWREG(contextPtr->port2Base + CPSW_PORT_SA_LO);
+ contextPtr->port1TxInCtl = HWREG(contextPtr->port1Base + CPSW_PORT_TX_IN_CTL);
+ contextPtr->port2TxInCtl = HWREG(contextPtr->port2Base + CPSW_PORT_TX_IN_CTL);
+ contextPtr->port1Vlan = HWREG(contextPtr->port1Base + CPSW_PORT_PORT_VLAN);
+ contextPtr->port2Vlan = HWREG(contextPtr->port2Base + CPSW_PORT_PORT_VLAN);
+ contextPtr->cpdmaRxFB = HWREG(contextPtr->cpdmaBase
+ + CPSW_CPDMA_RX_FREEBUFFER(0));
+ contextPtr->cpdmaTxCtl = HWREG(contextPtr->cpdmaBase
+ + CPSW_CPDMA_TX_CONTROL);
+ contextPtr->cpdmaRxCtl = HWREG(contextPtr->cpdmaBase
+ + CPSW_CPDMA_RX_CONTROL);
+ contextPtr->cpdmaRxHdp = HWREG(contextPtr->cpdmaBase
+ + CPSW_CPDMA_RX_HDP(0));
+ contextPtr->txIntMaskSet = HWREG(contextPtr->cpdmaBase
+ + CPSW_CPDMA_TX_INTMASK_SET);
+ contextPtr->wrCoreIntTxPulse = HWREG(contextPtr->wrBase
+ + CPSW_WR_C_RX_THRESH_EN(0) + 0x04);
+ contextPtr->rxIntMaskSet = HWREG(contextPtr->cpdmaBase
+ + CPSW_CPDMA_RX_INTMASK_SET);
+ contextPtr->wrCoreIntRxPulse = HWREG(contextPtr->wrBase
+ + CPSW_WR_C_RX_THRESH_EN(0) + 0x08);
+ contextPtr->sl1MacCtl = HWREG(contextPtr->sl1Base + CPSW_SL_MACCONTROL);
+ contextPtr->sl2MacCtl = HWREG(contextPtr->sl2Base + CPSW_SL_MACCONTROL);
+}
+
+/**
+ * \brief Restores the CPSW register context. This can be used while coming
+ * back from power down mode where CPSW power will be cut down.
+ *
+ * \param contextPtr Pointer to the structure where CPSW register context
+ * need to be restored from.
+ *
+ * \return None
+ *
+ **/
+void CPSWContextRestore(CPSWCONTEXT *contextPtr)
+{
+ unsigned int idx;
+ unsigned int *cppiDest = (unsigned int*)contextPtr->cppiRamBase;
+
+ /* Restore the CPPI RAM contents */
+ for(idx = 0; idx < (CPSW_SIZE_CPPI_RAM / 4); idx++, cppiDest++)
+ {
+ *cppiDest = contextPtr->cppiRam[idx] ;
+ }
+
+ HWREG(contextPtr->aleBase + CPSW_ALE_CONTROL) = contextPtr->aleCtrl;
+ HWREG(contextPtr->aleBase + CPSW_ALE_PORTCTL(0)) = contextPtr->alePortCtl[0];
+ HWREG(contextPtr->aleBase + CPSW_ALE_PORTCTL(1)) = contextPtr->alePortCtl[1];
+ HWREG(contextPtr->aleBase + CPSW_ALE_PORTCTL(2)) = contextPtr->alePortCtl[2];
+
+ for(idx = 0; idx < CPSW_MAX_NUM_ALE_ENTRY; idx++)
+ {
+ CPSWALETableEntrySet(contextPtr->aleBase, idx,
+ &(contextPtr->aleEntry[idx * 3]));
+ }
+
+ HWREG(contextPtr->ssBase + CPSW_SS_STAT_PORT_EN) = contextPtr->ssStatPortEn;
+ HWREG(contextPtr->port1Base + CPSW_PORT_SA_HI) = contextPtr->port1SaHi;
+ HWREG(contextPtr->port1Base + CPSW_PORT_SA_LO) = contextPtr->port1SaLo;
+ HWREG(contextPtr->port2Base + CPSW_PORT_SA_HI) = contextPtr->port2SaHi;
+ HWREG(contextPtr->port2Base + CPSW_PORT_SA_LO) = contextPtr->port2SaLo;
+ HWREG(contextPtr->port1Base + CPSW_PORT_TX_IN_CTL) = contextPtr->port1TxInCtl;
+ HWREG(contextPtr->port2Base + CPSW_PORT_TX_IN_CTL) = contextPtr->port2TxInCtl;
+ HWREG(contextPtr->port1Base + CPSW_PORT_PORT_VLAN) = contextPtr->port1Vlan;
+ HWREG(contextPtr->port2Base + CPSW_PORT_PORT_VLAN) = contextPtr->port2Vlan;
+ HWREG(contextPtr->cpdmaBase + CPSW_CPDMA_RX_FREEBUFFER(0)) =
+ contextPtr->cpdmaRxFB;
+ HWREG(contextPtr->cpdmaBase + CPSW_CPDMA_TX_CONTROL)
+ = contextPtr->cpdmaTxCtl;
+ HWREG(contextPtr->cpdmaBase + CPSW_CPDMA_RX_CONTROL)
+ = contextPtr->cpdmaRxCtl;
+ HWREG(contextPtr->cpdmaBase + CPSW_CPDMA_RX_HDP(0))
+ = contextPtr->cpdmaRxHdp;
+ HWREG(contextPtr->cpdmaBase + CPSW_CPDMA_TX_INTMASK_SET)
+ = contextPtr->txIntMaskSet;
+ HWREG(contextPtr->wrBase + CPSW_WR_C_RX_THRESH_EN(0) + 0x04)
+ = contextPtr->wrCoreIntTxPulse;
+ HWREG(contextPtr->cpdmaBase + CPSW_CPDMA_RX_INTMASK_SET)
+ = contextPtr->rxIntMaskSet;
+ HWREG(contextPtr->wrBase + CPSW_WR_C_RX_THRESH_EN(0) + 0x08)
+ = contextPtr->wrCoreIntRxPulse;
+ HWREG(contextPtr->sl1Base + CPSW_SL_MACCONTROL) = contextPtr->sl1MacCtl;
+ HWREG(contextPtr->sl2Base + CPSW_SL_MACCONTROL) = contextPtr->sl2MacCtl;
+}
+
+
diff --git a/cpsw/src/netif/cpsw_bb.c b/cpsw/src/netif/cpsw_bb.c
new file mode 100755
index 0000000..a35a6f0
--- /dev/null
+++ b/cpsw/src/netif/cpsw_bb.c
@@ -0,0 +1,161 @@
+/**
+ * \file cpsw.c
+ *
+ * \brief This file contains functions which configure CPSW instance
+ */
+
+/*
+* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+*/
+/*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include "soc_AM335x.h"
+#include "hw_control_AM335x.h"
+#include "hw_types.h"
+#include "beaglebone.h"
+#include "hw_cm_per.h"
+
+/******************************************************************************
+** INTERNAL MACRO DEFINITIONS
+******************************************************************************/
+#define CPSW_MII_SEL_MODE (0x00u)
+#define CPSW_MDIO_SEL_MODE (0x00u)
+#define LEN_MAC_ADDR (0x06u)
+#define OFFSET_MAC_ADDR (0x30u)
+
+/******************************************************************************
+** FUNCTION DEFINITIONS
+******************************************************************************/
+/**
+ * \brief This function selects the CPSW pins for use in MII mode.
+ *
+ * \param None
+ *
+ * \return None.
+ *
+ */
+void CPSWPinMuxSetup(void)
+{
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXERR) =
+ CONTROL_CONF_MII1_RXERR_CONF_MII1_RXERR_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXEN) = CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXDV) =
+ CONTROL_CONF_MII1_RXDV_CONF_MII1_RXDV_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD3) = CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD2) = CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD1) = CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD0) = CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXCLK) =
+ CONTROL_CONF_MII1_TXCLK_CONF_MII1_TXCLK_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXCLK) =
+ CONTROL_CONF_MII1_RXCLK_CONF_MII1_RXCLK_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD3) =
+ CONTROL_CONF_MII1_RXD3_CONF_MII1_RXD3_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD2) =
+ CONTROL_CONF_MII1_RXD2_CONF_MII1_RXD2_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD1) =
+ CONTROL_CONF_MII1_RXD1_CONF_MII1_RXD1_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD0) =
+ CONTROL_CONF_MII1_RXD0_CONF_MII1_RXD0_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_COL) =
+ CONTROL_CONF_MII1_COL_CONF_MII1_COL_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_CRS) =
+ CONTROL_CONF_MII1_CRS_CONF_MII1_CRS_RXACTIVE | CPSW_MII_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MDIO_DATA) =
+ CONTROL_CONF_MDIO_DATA_CONF_MDIO_DATA_RXACTIVE
+ | CONTROL_CONF_MDIO_DATA_CONF_MDIO_DATA_PUTYPESEL
+ | CPSW_MDIO_SEL_MODE;
+ HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MDIO_CLK) =
+ CONTROL_CONF_MDIO_CLK_CONF_MDIO_CLK_PUTYPESEL | CPSW_MDIO_SEL_MODE;
+}
+
+/**
+ * \brief Enables CPSW clocks
+ *
+ * \param None
+ *
+ * \return None.
+ */
+void CPSWClkEnable(void)
+{
+ HWREG(SOC_PRCM_REGS + CM_PER_CPGMAC0_CLKCTRL) =
+ CM_PER_CPGMAC0_CLKCTRL_MODULEMODE_ENABLE;
+
+ while(0 != (HWREG(SOC_PRCM_REGS + CM_PER_CPGMAC0_CLKCTRL)
+ & CM_PER_CPGMAC0_CLKCTRL_IDLEST));
+
+ HWREG(SOC_PRCM_REGS + CM_PER_CPSW_CLKSTCTRL) =
+ CM_PER_CPSW_CLKSTCTRL_CLKTRCTRL_SW_WKUP;
+
+ while(0 == (HWREG(SOC_PRCM_REGS + CM_PER_CPSW_CLKSTCTRL)
+ & CM_PER_CPSW_CLKSTCTRL_CLKACTIVITY_CPSW_125MHZ_GCLK));
+}
+
+/**
+ * \brief This function sets the MII mode for both ports
+ *
+ * \param None
+ *
+ * \return None.
+ */
+void EVMPortMIIModeSelect(void)
+{
+ /* Select MII, Internal Delay mode */
+ HWREG(SOC_CONTROL_REGS + CONTROL_GMII_SEL) = 0x00;
+}
+
+/**
+ * \brief This function returns the MAC address for the EVM
+ *
+ * \param addrIdx the MAC address index.
+ * \param macAddr the Pointer where the MAC address shall be stored
+ * 'addrIdx' can be either 0 or 1
+ *
+ * \return None.
+ */
+void EVMMACAddrGet(unsigned int addrIdx, unsigned char *macAddr)
+{
+ macAddr[0] = (HWREG(SOC_CONTROL_REGS + CONTROL_MAC_ID_LO(addrIdx))
+ >> 8) & 0xFF;
+ macAddr[1] = (HWREG(SOC_CONTROL_REGS + CONTROL_MAC_ID_LO(addrIdx)))
+ & 0xFF;
+ macAddr[2] = (HWREG(SOC_CONTROL_REGS + CONTROL_MAC_ID_HI(addrIdx))
+ >> 24) & 0xFF;
+ macAddr[3] = (HWREG(SOC_CONTROL_REGS + CONTROL_MAC_ID_HI(addrIdx))
+ >> 16) & 0xFF;
+ macAddr[4] = (HWREG(SOC_CONTROL_REGS + CONTROL_MAC_ID_HI(addrIdx))
+ >> 8) & 0xFF;
+ macAddr[5] = (HWREG(SOC_CONTROL_REGS + CONTROL_MAC_ID_HI(addrIdx)))
+ & 0xFF;
+}
+
+/****************************** End Of File *********************************/
diff --git a/cpsw/src/netif/cpswif.c b/cpsw/src/netif/cpswif.c
new file mode 100755
index 0000000..9ff45b0
--- /dev/null
+++ b/cpsw/src/netif/cpswif.c
@@ -0,0 +1,2999 @@
+/**
+ * @file - cpswif.c
+ * lwIP Ethernet interface for CPSW port
+ *
+ */
+
+/**
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/**
+ * Copyright (c) 2010 Texas Instruments Incorporated
+ *
+ * This file is dervied from the "ethernetif.c" skeleton Ethernet network
+ * interface driver for lwIP.
+ */
+#include <semaphore.h>
+#include <bsp.h>
+#include <sched.h>
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "netif/etharp.h"
+#include "netif/ppp/pppoe.h"
+#include "lwip/err.h"
+#include "netif/cpswif.h"
+#include "arch/cc.h"
+
+/* DriverLib Header Files required for this interface driver. */
+#include "cpsw.h"
+#include "mdio.h"
+#include "delay.h"
+#include "phy.h"
+#include "cache.h"
+
+#include "lwiplib.h"
+
+/* CPPI RAM size in bytes */
+#ifndef SIZE_CPPI_RAM
+#define SIZE_CPPI_RAM 0x2000
+#endif
+
+#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
+
+#define PORT_1 0x0
+#define PORT_2 0x1
+#define PORT_0_MASK 0x1
+#define PORT_1_MASK 0x2
+#define PORT_2_MASK 0x4
+#define HOST_PORT_MASK PORT_0_MASK
+#define SLAVE_PORT_MASK(slv_port_num) (1 << slv_port_num)
+#define PORT_MASK (0x7)
+#define INDV_PORT_MASK(slv_port_num) (1 << slv_port_num)
+
+#define ENTRY_TYPE 0x30
+#define ENTRY_TYPE_IDX 7
+#define ENTRY_FREE 0
+
+/* MDIO input and output frequencies in Hz */
+#define MDIO_FREQ_INPUT 125000000
+#define MDIO_FREQ_OUTPUT 1000000
+
+#define CPDMA_BUF_DESC_OWNER 0x20000000
+#define CPDMA_BUF_DESC_SOP 0x80000000
+#define CPDMA_BUF_DESC_EOP 0x40000000
+#define CPDMA_BUF_DESC_EOQ 0x10000000
+#define CPDMA_BUF_DESC_FROM_PORT 0x70000
+#define CPDMA_BUF_DESC_FROM_PORT_SHIFT 16
+#define CPDMA_BUF_DESC_TO_PORT(port) ((port << 16) | 0x100000)
+#define CPDMA_BD_LEN_MASK 0xFFFF
+#define CPDMA_BD_PKTLEN_MASK 0xFFFF
+
+#define MAX_TRANSFER_UNIT 1500
+#define PBUF_LEN_MAX 1520
+
+#define MIN_PKT_LEN 60
+
+/* Define those to better describe the network interface. */
+#define IFNAME0 'e'
+#define IFNAME1 'n'
+
+#define MASK_LOWER_4BITS_BYTE (0x0F)
+#define MASK UPPER_4BITS_BYTE (0xF0)
+
+#define MASK_BROADCAST_ADDR (0xFF)
+#define MASK_MULTICAST_ADDR (0x01)
+
+#define ALE_ENTRY_VLAN 0x20
+#define ALE_ENTRY_VLANUCAST 0x30
+#define ALE_ENTRY_UCAST 0x10
+#define ALE_ENTRY_MCAST 0xD0
+#define ALE_ENTRY_OUI (0x80)
+#define ALE_ENTRY_ADDR (0x10)
+#define ALE_ENTRY_VLAN_ADDR (0x30)
+#define ALE_VLAN_ENTRY_MEMBER_LIST 0
+#define ALE_VLAN_ENTRY_FRC_UNTAG_EGR 3
+#define ALE_VLAN_ENTRY_MCAST_UNREG (1)
+#define ALE_VLAN_ENTRY_MCAST_REG (2)
+#define ALE_VLAN_ENTRY_ID (3)
+#define ALE_VLAN_ID_MASK (0x0FFF)
+#define ALE_VLAN_ENTRY_ID_BIT0_BIT7 6
+#define ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11 7
+#define ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11_ALIGN (0x08)
+#define ALE_VLANUCAST_ENTRY_ID_BIT0_BIT7 6
+#define ALE_VLANUCAST_ENTRY_TYPE_ID_BIT8_BIT11 7
+#define ALE_UCAST_ENTRY_TYPE 7
+#define ALE_UCAST_TYPE_MASK (0xC0)
+#define ALE_UCAST_TYPE_SHIFT (6)
+#define ALE_UCAST_TYPE_PERSISTANT (0x00)
+#define ALE_UCAST_TYPE_UNTOUCHED (0x40)
+#define ALE_UCAST_TYPE_OUI (0x80)
+#define ALE_UCAST_TYPE_TOUCHED (0xC0)
+#define ALE_UCAST_ENTRY_DLR_PORT_BLK_SEC 8
+#define ALE_UCAST_ENTRY_DLR_BLK_SEC_MASK (0x03)
+#define ALE_UCAST_ENTRY_PORT_SHIFT 2
+#define ALE_MCAST_ENTRY_TYPE_FWD_STATE 7
+#define ALE_MCAST_ENTRY_TYPE_FWD_STATE_SHIFT (6)
+#define ALE_MCAST_ENTRY_PORTMASK_SUP 8
+#define ALE_MCAST_ENTRY_SUPER_MASK (0x02)
+#define ALE_MCAST_ENTRY_SUPER_SHIFT (1)
+#define ALE_MCAST_ENTRY_PORT_MASK (0x1C)
+#define ALE_MCAST_ENTRY_PORTMASK_SHIFT 2
+
+#define SELECT_10_HALF (1 << 0)
+#define SELECT_10_FULL (1 << 1)
+#define SELECT_100_HALF (1 << 2)
+#define SELECT_100_FULL (1 << 3)
+#define SELECT_1000_HALF (1 << 4)
+#define SELECT_1000_FULL (1 << 5)
+
+#define SELECT_SPEED_10 (0)
+#define SELECT_SPEED_100 (1)
+#define SELECT_SPEED_1000 (2)
+
+#define SELECT_FORCED (0)
+#define SELECT_AUTONEG (1)
+#define SELECT_BOTH (2)
+
+#define SELECT_HALF_DUPLEX (0)
+#define SELECT_FULL_DUPLEX (1)
+
+
+#define SEM_DEFAULT_PSHARED (0)
+#define SEM_INITIAL_VALUE (0)
+#define RX_PRIORITY (0)
+#define TX_PRIORITY (0)
+
+/**
+ * RX thread stack size.
+ */
+#define RX_THREAD_STACKSIZE 2048
+
+ /**
+ * RX thread stack size.
+ */
+#define TX_THREAD_STACKSIZE 2048
+
+static void rx_thread_function(void* arg);
+static void tx_thread_function(void* arg);
+
+/* TX Buffer descriptor data structure */
+struct cpdma_tx_bd {
+ volatile struct cpdma_tx_bd *next;
+ volatile u32_t bufptr;
+ volatile u32_t bufoff_len;
+ volatile u32_t flags_pktlen;
+
+ /* helper to know which pbuf this tx bd corresponds to */
+ volatile struct pbuf *pbuf;
+}cpdma_tx_bd;
+
+/* RX Buffer descriptor data structure */
+struct cpdma_rx_bd {
+ volatile struct cpdma_rx_bd *next;
+ volatile u32_t bufptr;
+ volatile u32_t bufoff_len;
+ volatile u32_t flags_pktlen;
+
+ /* helper to know which pbuf this rx bd corresponds to */
+ volatile struct pbuf *pbuf;
+}cpdma_rx_bd;
+
+/**
+ * Helper struct to hold the data used to operate on the receive
+ * buffer descriptor ring
+ */
+struct rxch {
+ /* The head of the bd chain which can be allocated for reception*/
+ volatile struct cpdma_rx_bd *free_head;
+
+ /* The head of the bd chain which is receiving data */
+ volatile struct cpdma_rx_bd *recv_head;
+
+ /* The tail of the bd chain which is receiving data */
+ volatile struct cpdma_rx_bd *recv_tail;
+
+ /* The number of free bd's, which can be allocated for reception */
+ volatile u32_t free_num;
+}rxch;
+
+/**
+ * Helper struct to hold the data used to operate on the transmit
+ * buffer descriptor ring
+ */
+struct txch {
+ /* The bd which is free to send */
+ volatile struct cpdma_tx_bd *free_head;
+
+ /* The head of the bd chain, being sent */
+ volatile struct cpdma_tx_bd *send_head;
+
+ /* The tail of the bd chain, being sent */
+ volatile struct cpdma_tx_bd *send_tail;
+
+ /* The number of free bd's, which can be sent */
+ volatile u32_t free_num;
+}txch;
+
+volatile struct cpdma_tx_bd *free_head;
+
+/**
+ * Slave port information
+ */
+struct cpswport{
+ u32_t port_base;
+ u32_t sliver_base;
+ u32_t phy_addr;
+
+ /* The PHY is capable of GitaBit or Not */
+ u32_t phy_gbps;
+}cpswport;
+
+/**
+ * CPSW instance information
+ */
+struct cpswinst{
+ /* Base addresses */
+ u32_t ss_base;
+ u32_t mdio_base;
+ u32_t wrpr_base;
+ u32_t ale_base;
+ u32_t cpdma_base;
+ u32_t cppi_ram_base;
+ u32_t host_port_base;
+
+ /* Slave port information */
+ struct cpswport port[MAX_SLAVEPORT_PER_INST];
+
+ /* The tx/rx channels for the interface */
+ struct txch txch;
+ struct rxch rxch;
+ sys_thread_t RxThread; /**< RX receive thread data object pointer */
+ sem_t rxsem;
+ sys_thread_t TxThread; /**< RX receive thread data object pointer */
+ sem_t txsem;
+ sys_mutex_t txmtx;
+}cpswinst;
+
+/* Defining set of CPSW base addresses for all the instances */
+static struct cpswinst cpsw_inst_data[MAX_CPSW_INST];
+
+/**
+* Function to setup the instance parameters inside the interface
+* @param cpswif The interface structure pointer
+* @return None.
+*/
+static void
+cpswif_inst_config(struct cpswportif *cpswif) {
+ u32_t inst_num = cpswif->inst_num;
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+
+ /**
+ * Code is added for only instance 0. If more instances
+ * are there, assign base addresses and phy info here
+ */
+ if(0 == inst_num) {
+ cpswinst->ss_base = CPSW0_SS_REGS;
+ cpswinst->mdio_base = CPSW0_MDIO_REGS;
+ cpswinst->wrpr_base = CPSW0_WR_REGS;
+ cpswinst->cpdma_base = CPSW0_CPDMA_REGS;
+ cpswinst->ale_base = CPSW0_ALE_REGS;
+ cpswinst->cppi_ram_base = CPSW0_CPPI_RAM_REGS;
+ cpswinst->host_port_base = CPSW0_PORT_0_REGS;
+ cpswinst->port[PORT_1].port_base = CPSW0_PORT_1_REGS;
+ cpswinst->port[PORT_1].sliver_base = CPSW0_SLIVER_1_REGS;
+#ifdef CPSW0_PORT_1_PHY_ADDR
+ cpswinst->port[PORT_1].phy_addr = CPSW0_PORT_1_PHY_ADDR;
+ cpswinst->port[PORT_1].phy_gbps = CPSW0_PORT_1_PHY_GIGABIT;
+#endif
+ cpswinst->port[PORT_2].port_base = CPSW0_PORT_2_REGS;
+ cpswinst->port[PORT_2].sliver_base = CPSW0_SLIVER_2_REGS;
+#ifdef CPSW0_PORT_2_PHY_ADDR
+ cpswinst->port[PORT_2].phy_addr = CPSW0_PORT_2_PHY_ADDR;
+ cpswinst->port[PORT_2].phy_gbps = CPSW0_PORT_2_PHY_GIGABIT;
+#endif
+ }
+}
+
+/**
+ * Gives the index of the ALE entry which is free
+ * @param cpswinst The CPSW instance structure pointer
+ *
+ * @return index of the ALE entry which is free
+ * ERR_VAL if entry not found
+ */
+static err_t
+cpswif_ale_entry_match_free(struct cpswinst *cpswinst) {
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS];
+ s32_t idx;
+
+ /* Check which ALE entry is free starting from 0th entry */
+ for (idx = 0; idx < MAX_ALE_ENTRIES; idx++) {
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
+
+ /* Break if the table entry is free */
+ if (((*(((u8_t *)ale_entry) + ENTRY_TYPE_IDX))
+ & ENTRY_TYPE) == ENTRY_FREE) {
+ return idx;
+ }
+ }
+
+ return ERR_VAL;
+}
+
+#ifdef CPSW_DUAL_MAC_MODE
+/**
+ * Sets the VLAN and VLAN/UCAST entries in ALE table for Dual Mac mode
+ * @param cpswinst The CPSW instance structure pointer
+ * @param port_num The slave port number
+ * @param eth_addr Ethernet address
+ *
+ * @return None
+ */
+static void
+cpswif_port_to_host_vlan_cfg(struct cpswinst *cpswinst, u32_t port_num,
+ u8_t *eth_addr)
+{
+ s32_t idx;
+ u32_t cnt;
+ u32_t ale_v_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+ u32_t ale_vu_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_free(cpswinst);
+
+ if(MAX_ALE_ENTRIES == idx) {
+ return;
+ }
+
+ /* Set up the VLAN Entry */
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_MEMBER_LIST) =
+ HOST_PORT_MASK | SLAVE_PORT_MASK(port_num);
+
+ /**
+ * Set the bit fields for entry type and VLAN ID. Set the port
+ * number as VLAN ID. So only lsb 2 bits of VLAN_ID field will be used.
+ */
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_ID_BIT0_BIT7) = port_num;
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11) = ALE_ENTRY_VLAN;
+
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_FRC_UNTAG_EGR) =
+ HOST_PORT_MASK | SLAVE_PORT_MASK(port_num);
+
+ /* Set the VLAN entry in the ALE table */
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_v_entry);
+
+ idx = cpswif_ale_entry_match_free(cpswinst);
+
+ if(MAX_ALE_ENTRIES == idx) {
+ return;
+ }
+
+ /* Set up the VLAN/Unicast Entry */
+ for(cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_vu_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ *(((u8_t *)ale_vu_entry) + ALE_VLANUCAST_ENTRY_TYPE_ID_BIT8_BIT11) =
+ ALE_ENTRY_VLANUCAST;
+ *(((u8_t *)ale_vu_entry) + ALE_VLANUCAST_ENTRY_ID_BIT0_BIT7) = port_num;
+
+ /* Set the VLAN/Unicast entry in the ALE table */
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_vu_entry);
+}
+
+#else /* CPSW_DUAL_MAC_MODE */
+
+/**
+ * Sets a unicast entry in the ALE table.
+ * @param cpswinst The CPSW instance structure pointer
+ * @param port_num The slave port number
+ * @param eth_addr Ethernet address
+ *
+ * @return None
+ */
+static void
+cpswif_ale_unicastentry_set(struct cpswinst *cpswinst, u32_t port_num,
+ u8_t *eth_addr) {
+ volatile u32_t cnt;
+ volatile s32_t idx;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ for(cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_TYPE) = ALE_ENTRY_UCAST;
+ *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_DLR_PORT_BLK_SEC) =
+ (port_num << ALE_UCAST_ENTRY_PORT_SHIFT);
+
+ idx = cpswif_ale_entry_match_free(cpswinst);
+
+ if (idx < MAX_ALE_ENTRIES ) {
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+ }
+}
+
+/**
+ * Sets a multicast entry in the ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param portmask The port mask for the port number
+ * @param eth_addr Ethernet Address
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static void
+cpswif_ale_multicastentry_set(struct cpswinst *cpswinst, u32_t portmask,
+ u8_t *eth_addr)
+{
+ volatile u32_t cnt;
+ volatile s32_t idx;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_free(cpswinst);
+ if (idx < MAX_ALE_ENTRIES ) {
+ for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) = ALE_ENTRY_MCAST;
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) |=
+ (portmask << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+ }
+}
+#endif /* CPSW_DUAL_MAC_MODE */
+
+#ifdef CPSW_SWITCH_CONFIG
+/**
+ * Checks the address is value for given type
+ *
+ * @param eth_addr Ethernet Address
+ * @param addr_type Type of address (Unicast, Multicast, Broadcast)
+ *
+ * @return the status
+ */
+static u32_t
+check_valid_addr(u8_t *eth_addr, u32_t addr_type) {
+ u32_t cnt = 0;
+
+ if (!addr_type)
+ return TRUE;
+
+ for (cnt = 0; cnt < LEN_MAC_ADDRESS; cnt++)
+ if ((eth_addr[cnt] & MASK_BROADCAST_ADDR) != MASK_BROADCAST_ADDR)
+ break;
+
+ if ((cnt == LEN_MAC_ADDRESS) && (addr_type == ADDR_TYPE_BROADCAST))
+ return TRUE;
+ else if (cnt == LEN_MAC_ADDRESS)
+ return FALSE;
+ else if (addr_type == ADDR_TYPE_BROADCAST)
+ return FALSE;
+
+ if (addr_type == ADDR_TYPE_MULTICAST) {
+ if ((eth_addr[0] & MASK_MULTICAST_ADDR) == MASK_MULTICAST_ADDR)
+ return TRUE;
+ } else if (addr_type == ADDR_TYPE_UNICAST) {
+ if ((eth_addr[0] & MASK_MULTICAST_ADDR) != MASK_MULTICAST_ADDR)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Gives the index of the ALE entry which is untouched ageable
+ * @param cpswinst The CPSW instance structure pointer
+ *
+ * @return index of the ALE entry which is free
+ * ERR_VAL if entry not found
+ */
+static err_t
+cpswif_ale_entry_match_ageable(struct cpswinst *cpswinst) {
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS];
+ u32_t type;
+ s32_t idx;
+
+ /* Check which ALE entry is free starting from 0th entry */
+ for (idx = 0; idx < MAX_ALE_ENTRIES; idx++) {
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
+
+ type = *(((u8_t *)ale_entry) + ENTRY_TYPE_IDX) & ENTRY_TYPE;
+
+ /* Goto next entry if the ale entry is not valid address */
+ if ((type != ALE_ENTRY_ADDR) && (type != ALE_ENTRY_VLAN_ADDR))
+ continue;
+
+ if (check_valid_addr((u8_t *)ale_entry, ADDR_TYPE_MULTICAST))
+ continue;
+
+ type = *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_TYPE) & ALE_UCAST_TYPE_MASK;
+
+ if ((type != ALE_UCAST_TYPE_PERSISTANT) && (type != ALE_UCAST_TYPE_OUI))
+ return idx;
+ }
+
+ return ERR_VAL;
+}
+
+/**
+ * Configure the rate limit for packets transmit of ports
+ * @param cpswinst The CPSW instance
+ * @param enable Enable Rate Limit
+ * @param direction Select TX or RX mode
+ * @param port_num Port Number
+ * @param addr_type Type of Address (Broadcast or Multicast)
+ * @param limit Vale of rate limit to be set
+ *
+ * @return None
+ *
+ **/
+static void
+cpswif_rate_limit(struct cpswinst *cpswinst, u32_t enable, u32_t direction,
+ u32_t port_num, u32_t addr_type, u32_t limit) {
+ if (!enable) {
+ CPSWALERateLimitDisable(cpswinst->ale_base);
+ }
+
+ if (addr_type == ADDR_TYPE_BROADCAST) {
+ CPSWALEBroadcastRateLimitSet(cpswinst->ale_base, port_num, limit);
+ } else if (addr_type == ADDR_TYPE_MULTICAST) {
+ CPSWALEMulticastRateLimitSet(cpswinst->ale_base, port_num, limit);
+ }
+
+ if (port_num == 0) {
+ if (direction) {
+ CPSWALERateLimitTXMode(cpswinst->ale_base);
+ } else {
+ CPSWALERateLimitRXMode(cpswinst->ale_base);
+ }
+ } else {
+ if (direction) {
+ CPSWALERateLimitRXMode(cpswinst->ale_base);
+ } else {
+ CPSWALERateLimitTXMode(cpswinst->ale_base);
+ }
+ }
+
+ CPSWALERateLimitEnable(cpswinst->ale_base);
+}
+
+/**
+ * Gives the index of the ALE entry which match address of VLAN
+ * @param cpswinst The CPSW instance structure pointer
+ * @param eth_addr Ethernet address
+ * @param vid VLAN ID
+ *
+ * @return index of the ALE entry which match address of VLAN
+ * ERR_VAL if entry not found
+ */
+static err_t
+cpswif_ale_entry_match_addr(struct cpswinst *cpswinst, u8_t *eth_addr,
+ u32_t vid) {
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS];
+ u32_t type, cnt;
+ s32_t idx;
+
+ /* Check which ALE entry is free starting from 0th entry */
+ for (idx = 0; idx < MAX_ALE_ENTRIES; idx++) {
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
+
+ type = *(((u8_t *)ale_entry) + ENTRY_TYPE_IDX) & ENTRY_TYPE;
+
+ /* Goto next entry if the ale entry is not valid address */
+ if ((type != ALE_ENTRY_ADDR) && (type != ALE_ENTRY_VLAN_ADDR))
+ continue;
+
+ if ((*(((u16_t *)ale_entry) + ALE_VLAN_ENTRY_ID) & ALE_VLAN_ID_MASK) != vid)
+ continue;
+
+ for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ if (*(((u8_t *)ale_entry) + cnt) != eth_addr[ETHARP_HWADDR_LEN - cnt -1])
+ break;
+
+ if (ETHARP_HWADDR_LEN == (cnt + 1))
+ return idx;
+ }
+ }
+
+ return ERR_VAL;
+}
+
+/**
+ * Gives the index of the ALE entry which match vlan
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ *
+ * @return index of the ALE entry which match vlan
+ * ERR_VAL if entry not found
+ */
+static err_t
+cpswif_ale_entry_match_vlan(struct cpswinst *cpswinst, u32_t vid) {
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS];
+ u32_t type;
+ s32_t idx;
+
+ /* Check which ALE entry is free starting from 0th entry */
+ for (idx = 0; idx < MAX_ALE_ENTRIES; idx++) {
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
+
+ type = *(((u8_t *)ale_entry) + ENTRY_TYPE_IDX) & ENTRY_TYPE;
+
+ /* Goto next entry if the ale entry is not valid vlan */
+ if (type != ALE_ENTRY_VLAN)
+ continue;
+
+ if ((*(((u16_t *)ale_entry) + ALE_VLAN_ENTRY_ID) & ALE_VLAN_ID_MASK) == vid)
+ return idx;
+ }
+
+ return ERR_VAL;
+}
+
+/**
+ * Adds an unicast entry in the ALE table.
+ * @param cpswinst The CPSW instance structure pointer
+ * @param port_num The slave port number
+ * @param eth_addr Ethernet address
+ * @param flags Flags Settings
+ * 0x1 - Secure
+ * 0x2 - Block
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static err_t
+cpswif_ale_unicastentry_add(struct cpswinst *cpswinst, u32_t port_num,
+ u8_t *eth_addr, u32_t flags, u32_t ucast_type) {
+ volatile u32_t cnt;
+ volatile s32_t idx;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, 0);
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_free(cpswinst);
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_ageable(cpswinst);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ for(cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_TYPE) = ALE_ENTRY_ADDR |
+ (ucast_type << ALE_UCAST_TYPE_SHIFT);
+ *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_DLR_PORT_BLK_SEC) =
+ (port_num << ALE_UCAST_ENTRY_PORT_SHIFT) |
+ (flags & ALE_UCAST_ENTRY_DLR_BLK_SEC_MASK);
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+
+ return idx;
+}
+
+/**
+ * Adds an OUI entry in the ALE table.
+ * @param cpswinst The CPSW instance structure pointer
+ * @param eth_addr Ethernet address
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static err_t
+cpswif_ale_OUI_add(struct cpswinst *cpswinst, u8_t *eth_addr) {
+ volatile u32_t cnt;
+ volatile s32_t idx;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, 0);
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_free(cpswinst);
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_ageable(cpswinst);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ for(cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_TYPE) = ALE_ENTRY_ADDR | ALE_ENTRY_OUI;
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+
+ return idx;
+}
+
+/**
+ * Deletes an unicast entry in the ALE table.
+ * @param cpswinst The CPSW instance structure pointer
+ * @param port_num The slave port number
+ * @param eth_addr Ethernet address
+ *
+ * @return index of the ALE entry deleted
+ * ERR_VAL if table entry is not present
+ */
+static err_t
+cpswif_ale_unicastentry_del(struct cpswinst *cpswinst, u32_t port_num,
+ u8_t *eth_addr) {
+ volatile s32_t idx;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_TYPE) = ENTRY_FREE;
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, 0);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+
+ return idx;
+}
+
+/**
+ * Adds a multicast entry in the ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param portmask The port mask for the port number
+ * @param eth_addr Ethernet Address
+ * @param super Supervisory Packet
+ * @param mcast_st Multicast Forward State
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static err_t
+cpswif_ale_multicastentry_add(struct cpswinst *cpswinst, u32_t portmask,
+ u8_t *eth_addr, u32_t super, u32_t mcast_st) {
+ volatile s32_t idx;
+ volatile u32_t cnt;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, 0);
+
+ if (ERR_VAL == idx) {
+ idx = cpswif_ale_entry_match_free(cpswinst);
+ } else {
+ /* Get the entry in the ALE table */
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
+ }
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_ageable(cpswinst);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ portmask |= (*(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) &
+ ALE_MCAST_ENTRY_PORT_MASK);
+
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) =
+ (ALE_ENTRY_ADDR |
+ (mcast_st << ALE_MCAST_ENTRY_TYPE_FWD_STATE_SHIFT));
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) &=
+ ~(PORT_MASK << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) |=
+ (portmask << ALE_MCAST_ENTRY_PORTMASK_SHIFT) |
+ ((super << ALE_MCAST_ENTRY_SUPER_SHIFT) &
+ ALE_MCAST_ENTRY_SUPER_MASK);
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+
+ return idx;
+}
+
+/**
+ * Deletes a multicast entry in the ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param portmask The port mask for the port number
+ * @param eth_addr Ethernet Address
+ *
+ * @return index of the ALE entry deleted
+ * ERR_VAL if table entry is not present
+ */
+static err_t
+cpswif_ale_multicastentry_del(struct cpswinst *cpswinst, u32_t portmask,
+ u8_t *eth_addr) {
+ volatile s32_t idx;
+ u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, 0);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
+
+ if (portmask) {
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) &=
+ ~(PORT_MASK << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) =
+ (portmask << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+ } else {
+ *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) = ENTRY_FREE;
+ }
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
+
+ return idx;
+}
+
+/**
+ * Adds the VLAN entry in ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ * @param port_num The slave port number
+ * @param untag The force untagged egress
+ * @param reg_mcast The registered MCAST Flood Mask
+ * @param unreg_mcast The unregistered MCAST Flood Mask
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static err_t
+cpswif_ale_vlan_add(struct cpswinst *cpswinst, u32_t vid, u32_t port_num,
+ u32_t untag, u32_t reg_mcast, u32_t unreg_mcast) {
+ s32_t idx;
+ u32_t ale_v_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_vlan(cpswinst, vid);
+
+ if (ERR_VAL == idx) {
+ idx = cpswif_ale_entry_match_free(cpswinst);
+ } else {
+ /* Get the entry in the ALE table */
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_v_entry);
+ }
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_ageable(cpswinst);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ /**
+ * Set the bit fields for entry type and VLAN ID.
+ */
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_ID_BIT0_BIT7) = vid;
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11) =
+ ((vid >> ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11_ALIGN) &
+ MASK_LOWER_4BITS_BYTE) | ALE_ENTRY_VLAN;
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_FRC_UNTAG_EGR) = untag;
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_MCAST_UNREG) = unreg_mcast;
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_MCAST_REG) = reg_mcast;
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_MEMBER_LIST) |=
+ PORT_MASK & INDV_PORT_MASK(port_num);
+
+ /* Set the VLAN entry in the ALE table */
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_v_entry);
+
+ return idx;
+}
+
+/**
+ * Dlelete the VLAN entry in ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ * @param port_num The slave port number
+ *
+ * @return index of the ALE entry deleted
+ * ERR_VAL if table entry is not present
+ */
+static err_t
+cpswif_ale_vlan_del(struct cpswinst *cpswinst, u32_t vid, u32_t port_num) {
+ s32_t idx;
+ u32_t mask;
+ u32_t ale_v_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_vlan(cpswinst, vid);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_v_entry);
+
+ /* Set up the VLAN Entry */
+ mask = *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_MEMBER_LIST) | PORT_MASK;
+ mask &= INDV_PORT_MASK(port_num);
+
+ if (0 == mask)
+ return ERR_VAL;
+
+ if (1 == mask) {
+ *(((u8_t *)ale_v_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) = ENTRY_FREE;
+ } else {
+ /* Set up the VLAN Entry */
+ *(((u8_t *)ale_v_entry) + ALE_VLAN_ENTRY_MEMBER_LIST) &=
+ ~INDV_PORT_MASK(port_num);
+ }
+
+ /* Set the VLAN/Unicast entry in the ALE table */
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_v_entry);
+
+ return idx;
+}
+
+/**
+ * Add the VLAN/UCAST entries in ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ * @param port_num The slave port number
+ * @param eth_addr Ethernet address
+ * @param flags Flags Settings
+ * 0x1 - Secure
+ * 0x2 - Block
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static err_t
+cpswif_ale_vlan_add_ucast(struct cpswinst *cpswinst, u32_t vid, u32_t port_num,
+ u8_t *eth_addr, u32_t flags, u32_t ucast_type) {
+ s32_t idx;
+ u32_t cnt;
+ u32_t ale_vu_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, vid);
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_free(cpswinst);
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_ageable(cpswinst);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ /**
+ * Set the bit fields for entry type and VLAN ID.
+ */
+ *(((u8_t *)ale_vu_entry) + ALE_VLAN_ENTRY_ID_BIT0_BIT7) = vid;
+ *(((u8_t *)ale_vu_entry) + ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11) =
+ ((vid >> ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11_ALIGN) &
+ MASK_LOWER_4BITS_BYTE) | ALE_ENTRY_VLAN_ADDR |
+ (ucast_type << ALE_UCAST_TYPE_SHIFT);
+
+ for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_vu_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ *(((u8_t *)ale_vu_entry) + ALE_UCAST_ENTRY_DLR_PORT_BLK_SEC) =
+ (port_num << ALE_UCAST_ENTRY_PORT_SHIFT) |
+ (flags & ALE_UCAST_ENTRY_DLR_BLK_SEC_MASK);
+
+ /* Set the VLAN entry in the ALE table */
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_vu_entry);
+
+ return idx;
+}
+
+/**
+ * Dlelete the VLAN/UCAST entry in ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ * @param port_num The slave port number
+ *
+ * @return index of the ALE entry deleted
+ * ERR_VAL if table entry is not present
+ */
+static err_t
+cpswif_ale_vlan_del_ucast(struct cpswinst *cpswinst, u32_t vid, u32_t port_num,
+ u8_t *eth_addr) {
+ volatile s32_t idx;
+ u32_t ale_vu_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ *(((u8_t *)ale_vu_entry) + ALE_UCAST_ENTRY_TYPE) = ENTRY_FREE;
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, vid);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_vu_entry);
+
+ return idx;
+}
+
+/**
+ * Add the VLAN/MCAST entries in ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ * @param port_num The slave port number
+ * @param eth_addr Ethernet address
+ * @param super Supervisory Packet
+ * @param mcast_st Multicast Forward State
+ *
+ * @return index of the ALE entry added
+ * ERR_VAL if table entry is not free
+ */
+static err_t
+cpswif_ale_vlan_add_mcast(struct cpswinst *cpswinst, u32_t vid, u32_t portmask,
+ u8_t *eth_addr, u32_t super, u32_t mcast_st) {
+ s32_t idx;
+ u32_t cnt;
+ u32_t ale_vm_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, vid);
+
+ if (ERR_VAL == idx) {
+ idx = cpswif_ale_entry_match_free(cpswinst);
+ } else {
+ /* Get the entry in the ALE table */
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_vm_entry);
+ }
+
+ if (ERR_VAL == idx)
+ idx = cpswif_ale_entry_match_ageable(cpswinst);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ /**
+ * Set the bit fields for entry type and VLAN ID.
+ */
+ *(((u8_t *)ale_vm_entry) + ALE_VLAN_ENTRY_ID_BIT0_BIT7) = vid;
+ *(((u8_t *)ale_vm_entry) + ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11) =
+ ((vid >> ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11_ALIGN) &
+ MASK_LOWER_4BITS_BYTE);
+
+ for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
+ *(((u8_t *)ale_vm_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt -1];
+ }
+
+ portmask |= (*(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) &
+ ALE_MCAST_ENTRY_PORT_MASK);
+
+ *(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) |=
+ (ALE_ENTRY_VLAN_ADDR |
+ (mcast_st << ALE_MCAST_ENTRY_TYPE_FWD_STATE_SHIFT));
+ *(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) &=
+ ~(PORT_MASK << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+ *(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) |=
+ (portmask << ALE_MCAST_ENTRY_PORTMASK_SHIFT) |
+ ((super << ALE_MCAST_ENTRY_SUPER_SHIFT) &
+ ALE_MCAST_ENTRY_SUPER_MASK);
+
+ /* Set the VLAN entry in the ALE table */
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_vm_entry);
+
+ return idx;
+}
+
+/**
+ * Deletes a vlan multicast entry in the ALE table
+ * @param cpswinst The CPSW instance structure pointer
+ * @param vid VLAN ID
+ * @param portmask The port mask for the port number
+ * @param eth_addr Ethernet Address
+ *
+ * @return index of the ALE entry deleted
+ * ERR_VAL if table entry is not present
+ */
+static err_t
+cpswif_ale_vlan_del_mcast(struct cpswinst *cpswinst, u32_t vid, u32_t portmask,
+ u8_t *eth_addr) {
+ volatile s32_t idx;
+ u32_t ale_vm_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
+
+ idx = cpswif_ale_entry_match_addr(cpswinst, eth_addr, vid);
+
+ if (ERR_VAL == idx)
+ return ERR_VAL;
+
+ CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_vm_entry);
+
+ if (portmask) {
+ *(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) &=
+ ~(PORT_MASK << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+ *(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) =
+ (portmask << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
+ } else {
+ *(((u8_t *)ale_vm_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) = ENTRY_FREE;
+ }
+
+ CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_vm_entry);
+
+ return idx;
+}
+
+#endif /* CPSW_SWITCH_CONFIG */
+
+/**
+ * AutoNegotiates with phy for link, set it in silver and check for link status.
+ * @param cpswinst The CPSW instance structure pointer
+ * @param port_num The slave port number
+ * @param adv Configuration for advertisement
+ * SELECT_10_HALF - 10Base Half Duplex
+ * SELECT_10_FULL - 10Base Full Duplex
+ * SELECT_100_HALF - 100Base Half Duplex
+ * SELECT_100_FULL - 100Base Full Duplex
+ * SELECT_1000_HALF - 1000Base Half Duplex
+ * SELECT_1000_FULL - 1000Base Full Duplex
+ * @return ERR_OK If link set up is successful
+ * others if not successful
+ */
+static err_t
+cpswif_phy_autoneg(struct cpswinst *cpswinst, u32_t port_num, u32_t adv) {
+ err_t linkstat = ERR_CONN;
+ u16_t adv_val = 0, partnr_ablty = 0, gbps_partnr_ablty = 0, gig_adv_val = 0;
+ u32_t aut_neg_cnt = 200, auto_stat, transfer_mode = 0;
+
+ /* Check if ethernet PHY is present or not */
+ if (0 == (MDIOPhyAliveStatusGet(cpswinst->mdio_base)
+ & (1 << cpswinst->port[port_num - 1].phy_addr))) {
+ LWIP_PRINTF("\n\rNo PHY found at addr %d for Port %d of Instance %d.",
+ cpswinst->port[port_num - 1].phy_addr,
+ port_num, 0);
+ return linkstat;
+ }
+
+ LWIP_PRINTF("\n\rPHY found at address %d for Port %d of Instance %d.",
+ cpswinst->port[port_num - 1].phy_addr,
+ port_num, 0);
+
+ if (SELECT_1000_HALF == adv) {
+ LWIP_PRINTF("\n\rCPSW doesnot support Half Duplex for Gigabyte...");
+ return linkstat;
+ }
+
+ /* We advertise for 10/100 Mbps both half and full duplex */
+ if (adv & SELECT_10_HALF)
+ adv_val |= PHY_10BT;
+ if (adv & SELECT_10_FULL)
+ adv_val |= PHY_10BT_FD;
+ if (adv & SELECT_100_HALF)
+ adv_val |= PHY_100BTX;
+ if (adv & SELECT_100_FULL)
+ adv_val |= PHY_100BTX_FD;
+
+ gig_adv_val = 0;
+ partnr_ablty = TRUE;
+ gbps_partnr_ablty = FALSE;
+
+ /**
+ * Not all the PHYs can operate at 1000 Mbps. So advertise only
+ * if the PHY is capable
+ */
+ if (cpswinst->port[port_num -1].phy_gbps) {
+ LWIP_PRINTF("\n\rPhy supports Gigabyte...");
+ if (adv & SELECT_1000_FULL) {
+ gig_adv_val = PHY_1000BT_FD;
+ partnr_ablty = TRUE;
+ gbps_partnr_ablty = TRUE;
+ }
+ if (adv & SELECT_1000_HALF) {
+ LWIP_PRINTF("\n\rCPSW doesnot support Half Duplex for Gigabyte...");
+ }
+ } else {
+ LWIP_PRINTF("\n\rPhy doesnot support Gigabyte...");
+ }
+
+ LWIP_PRINTF("\n\rPerforming Auto-Negotiation...");
+
+ /**
+ * Now start Autonegotiation. PHY will talk to its partner
+ * and give us what the partner can handle
+ */
+ if (PhyAutoNegotiate(cpswinst->mdio_base,
+ cpswinst->port[port_num -1].phy_addr,
+ &adv_val, &gig_adv_val) == TRUE) {
+ while (aut_neg_cnt) {
+ delay(50);
+ auto_stat = PhyAutoNegStatusGet(cpswinst->mdio_base,
+ cpswinst->port[port_num -1].phy_addr);
+ if (TRUE == auto_stat) {
+ break;
+ }
+ aut_neg_cnt--;
+ }
+
+ if (0 != aut_neg_cnt) {
+ linkstat = ERR_OK;
+ LWIP_PRINTF("\n\rAuto-Negotiation Successful.");
+ } else {
+ LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
+ return ERR_CONN;
+ }
+
+ /* Get what the partner supports */
+ PhyPartnerAbilityGet(cpswinst->mdio_base,
+ cpswinst->port[port_num -1].phy_addr,
+ &partnr_ablty, &gbps_partnr_ablty);
+ if (gbps_partnr_ablty & PHY_LINK_PARTNER_1000BT_FD) {
+ LWIP_PRINTF("\n\rTransfer Mode : 1000 Mbps.");
+ transfer_mode = CPSW_SLIVER_GIG_FULL_DUPLEX;
+ } else {
+ if ((adv_val & partnr_ablty) & PHY_100BTX_FD) {
+ LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Full Duplex.");
+ transfer_mode = CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
+ } else if ((adv_val & partnr_ablty) & PHY_100BTX) {
+ LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Half Duplex.");
+ transfer_mode = CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
+ } else if ((adv_val & partnr_ablty) & PHY_10BT_FD) {
+ LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Full Duplex.");
+ transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
+ } else if ((adv_val & partnr_ablty) & PHY_10BT) {
+ LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Half Duplex.");
+ transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
+ } else {
+ LWIP_PRINTF("\n\rNo Valid Transfer Mode is detected.");
+ }
+ }
+ } else {
+ LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
+ linkstat = ERR_CONN;
+ }
+
+ /**
+ * Set the Sliver with the negotiation results if autonegotiation
+ * is successful
+ */
+ if (linkstat == ERR_OK) {
+ CPSWSlTransferModeSet(cpswinst->port[port_num - 1].sliver_base,
+ transfer_mode);
+ }
+
+ /* Check if PHY link is there or not */
+ if (FALSE == ((PhyLinkStatusGet(cpswinst->mdio_base,
+ cpswinst->port[port_num - 1].phy_addr, 1000)))) {
+ LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Inst %d.",
+ port_num, 0);
+ return linkstat;
+ }
+
+ LWIP_PRINTF("\n\rPHY link verified for Port %d of Instance %d.",
+ port_num, 0);
+
+ CPSWSlRGMIIEnable(
+ cpswinst->port[port_num - 1].sliver_base);
+
+ return linkstat;
+}
+
+/**
+ * Manually configure phy, set it in silver and check for link status.
+ * @param cpswinst The CPSW instance structure pointer
+ * @param port_num The slave port number
+ * @param speed Configuration for speed
+ * SELECT_SPEED_1000 - 1000 Mbps
+ * SELECT_SPEED_100 - 100 Mbps
+ * SELECT_SPEED_10 - 10 Mbps
+ * @param duplex Configuration for duplex
+ * SELECT_HALF_DUPLEX - Half Duplex
+ * SELECT_FULL_DUPLEX - Full Duplex
+ * @return ERR_OK If link set up is successful
+ * others if not successful
+ */
+static err_t
+cpswif_phy_forced(struct cpswinst *cpswinst, u32_t port_num, u32_t speed,
+ u32_t duplex) {
+ err_t linkstat = ERR_CONN;
+ u16_t speed_val = 0, duplex_val = 0;
+ u32_t frc_stat_cnt = 200, frc_stat = FALSE, transfer_mode = 0;
+
+ /* Check if ethernet PHY is present or not */
+ if (0 == (MDIOPhyAliveStatusGet(cpswinst->mdio_base)
+ & (1 << cpswinst->port[port_num - 1].phy_addr))){
+ LWIP_PRINTF("\n\rNo PHY found at addr %d for Port %d of Instance %d.",
+ cpswinst->port[port_num - 1].phy_addr,
+ port_num, 0);
+ return linkstat;
+ }
+
+ LWIP_PRINTF("\n\rPHY found at address %d for Port %d of Instance %d.",
+ cpswinst->port[port_num - 1].phy_addr,
+ port_num, 0);
+
+ /* configure control for speed and duples */
+ if (SELECT_SPEED_1000 == speed)
+ speed_val = PHY_SPEED_1000MBPS;
+ else if (SELECT_SPEED_100 == speed)
+ speed_val = PHY_SPEED_100MBPS;
+
+ if (TRUE == duplex)
+ duplex_val = PHY_FULL_DUPLEX;
+
+ if (SELECT_SPEED_1000 == speed) {
+ LWIP_PRINTF("\n\rManual Configuration not allowed for Gigabyte...");
+ return linkstat;
+ }
+
+ if (FALSE == PhyReset(cpswinst->mdio_base,
+ cpswinst->port[port_num - 1].phy_addr)) {
+ LWIP_PRINTF("\n\rPHY Reset Failed...");
+ return linkstat;
+ }
+
+ if (TRUE == (PhyLinkStatusGet(cpswinst->mdio_base,
+ cpswinst->port[port_num - 1].phy_addr, 1000))) {
+ while (frc_stat_cnt) {
+ delay(50);
+ /* Check if PHY link is there or not */
+ frc_stat = (PhyLinkStatusGet(cpswinst->mdio_base,
+ cpswinst->port[port_num - 1].phy_addr, 1000));
+
+ if (TRUE == frc_stat) {
+ LWIP_PRINTF("\n\rPHY Link is Down.");
+ break;
+ }
+ frc_stat_cnt--;
+ }
+ }
+
+ LWIP_PRINTF("\n\rPerforming Manual Configuration...");
+
+ frc_stat_cnt = 200;
+ frc_stat = FALSE;
+
+ if (PhyConfigure(cpswinst->mdio_base, cpswinst->port[port_num -1].phy_addr,
+ speed_val, duplex_val)) {
+ while (frc_stat_cnt) {
+ delay(50);
+ frc_stat = PhyLinkStatusGet(cpswinst->mdio_base,
+ cpswinst->port[port_num - 1].phy_addr, 1000);
+
+ if (1 == frc_stat) {
+ break;
+ }
+ frc_stat_cnt--;
+ }
+
+ if (0 != frc_stat_cnt) {
+ linkstat = ERR_OK;
+ LWIP_PRINTF("\n\rPhy Configuration Successful.");
+ LWIP_PRINTF("\n\rPHY link verified for Port %d of Instance %d.",
+ port_num, 0);
+ } else {
+ LWIP_PRINTF("\n\rPhy Configuration Successful.");
+ LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Inst %d.",
+ port_num, 0);
+ return ERR_CONN;
+ }
+
+ if (SELECT_SPEED_1000 == speed) {
+ LWIP_PRINTF("\n\rTransfer Mode : 1000 Mbps.");
+ transfer_mode = CPSW_SLIVER_GIG_FULL_DUPLEX;
+ } else {
+ if (SELECT_SPEED_10 == speed) {
+ LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps ");
+ transfer_mode = CPSW_SLIVER_INBAND;
+ } else {
+ LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps ");
+ }
+ if (TRUE == duplex) {
+ LWIP_PRINTF("Full Duplex.");
+ transfer_mode |= CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
+ } else {
+ LWIP_PRINTF("Half Duplex.");
+ transfer_mode |= CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
+ }
+ }
+ } else {
+ LWIP_PRINTF("\n\rPhy Configuration Not Successful.");
+ LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Inst %d.",
+ port_num, 0);
+ linkstat = ERR_CONN;
+ }
+
+ /**
+ * Set the Sliver with the forced phy configuration
+ */
+ CPSWSlTransferModeSet(cpswinst->port[port_num - 1].sliver_base,
+ transfer_mode);
+
+ CPSWSlRGMIIEnable(cpswinst->port[port_num - 1].sliver_base);
+
+ return linkstat;
+}
+
+/**
+* Function to setup the link. AutoNegotiates with the phy for link
+* setup and set the CPSW with the result of autonegotiation.
+* @param cpswportif The cpsw port interface structure pointer
+* @return ERR_OK If link set up is successful
+* others if not successful
+*/
+static err_t
+cpswif_autoneg_config(u32_t inst_num, u32_t port_num) {
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+ err_t linkstat = ERR_CONN;
+ u16_t adv_val, partnr_ablty, gbps_partnr_ablty, gig_adv_val;
+ u32_t aut_neg_cnt = 200, auto_stat, transfer_mode = 0;
+
+ /* We advertise for 10/100 Mbps both half and full duplex */
+ adv_val = (PHY_100BTX | PHY_100BTX_FD | PHY_10BT | PHY_10BT_FD);
+
+ /**
+ * Not all the PHYs can operate at 1000 Mbps. So advertise only
+ * if the PHY is capable
+ */
+ if(TRUE == cpswinst->port[port_num -1].phy_gbps) {
+ gig_adv_val = PHY_1000BT_FD;
+ partnr_ablty = TRUE;
+ gbps_partnr_ablty = TRUE;
+ } else {
+ gig_adv_val = 0;
+ partnr_ablty = TRUE;
+ gbps_partnr_ablty = FALSE;
+ }
+
+ LWIP_PRINTF("\n\rPerforming Auto-Negotiation...");
+
+ /**
+ * Now start Autonegotiation. PHY will talk to its partner
+ * and give us what the partner can handle
+ */
+ if(PhyAutoNegotiate(cpswinst->mdio_base,
+ cpswinst->port[port_num -1].phy_addr,
+ &adv_val, &gig_adv_val) == TRUE) {
+ while(aut_neg_cnt) {
+ delay(50);
+ auto_stat = PhyAutoNegStatusGet(cpswinst->mdio_base,
+ cpswinst->port[port_num -1].phy_addr);
+ if(TRUE == auto_stat) {
+ break;
+ }
+ aut_neg_cnt--;
+ }
+
+ if(0 != aut_neg_cnt) {
+ linkstat = ERR_OK;
+ LWIP_PRINTF("\n\rAuto-Negotiation Successful.");
+ } else {
+ LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
+ return ERR_CONN;
+ }
+
+ /* Get what the partner supports */
+ PhyPartnerAbilityGet(cpswinst->mdio_base,
+ cpswinst->port[port_num -1].phy_addr,
+ &partnr_ablty, &gbps_partnr_ablty);
+ if(gbps_partnr_ablty & PHY_LINK_PARTNER_1000BT_FD) {
+ LWIP_PRINTF("\n\rTransfer Mode : 1000 Mbps.");
+ transfer_mode = CPSW_SLIVER_GIG_FULL_DUPLEX;
+ } else {
+ if ((adv_val & partnr_ablty) & PHY_100BTX_FD) {
+ LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Full Duplex.");
+ transfer_mode = CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
+ } else if ((adv_val & partnr_ablty) & PHY_100BTX) {
+ LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Half Duplex.");
+ transfer_mode = CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
+ } else if ((adv_val & partnr_ablty) & PHY_10BT_FD) {
+ LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Full Duplex.");
+ transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
+ } else if ((adv_val & partnr_ablty) & PHY_10BT) {
+ LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Half Duplex.");
+ transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
+ } else {
+ LWIP_PRINTF("\n\rNo Valid Transfer Mode is detected.");
+ }
+ }
+ } else {
+ LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
+ linkstat = ERR_CONN;
+ }
+
+ /**
+ * Set the Sliver with the negotiation results if autonegotiation
+ * is successful
+ */
+ if(linkstat == ERR_OK) {
+ CPSWSlTransferModeSet(cpswinst->port[port_num - 1].sliver_base,
+ transfer_mode);
+ }
+
+ return linkstat;
+}
+
+/**
+ * This function allocates the rx buffer descriptors ring. The function
+ * internally calls pbuf_alloc() and allocates the pbufs to the rx buffer
+ * descriptors.
+ *
+ * @param cpswinst The CPSW instance structure pointer
+ * @return None
+ */
+static void
+cpswif_rxbd_alloc(struct cpswinst *cpswinst) {
+ struct rxch *rxch = &(cpswinst->rxch);
+ struct pbuf *p;
+ volatile struct cpdma_rx_bd *curr_bd, *last_bd, *recv_tail, *recv_head;
+ u32_t saved_free_num;
+
+ /* Start from the free head of the chain */
+ curr_bd = rxch->free_head;
+
+ /* Note down the current positions */
+ recv_head = rxch->free_head;
+ recv_tail = rxch->recv_tail;
+ saved_free_num = rxch->free_num;
+ last_bd = rxch->recv_tail;
+
+ while(rxch->free_num) {
+ /**
+ * Try to get a pbuf of max. length. This shall be cache line aligned if
+ * cache is enabled.
+ */
+ p = pbuf_alloc(PBUF_RAW, PBUF_LEN_MAX, PBUF_POOL);
+
+ /**
+ * Allocate bd's if p is not NULL. This allocation doesnt support
+ * pbuf chaining.
+ */
+ if(p != NULL) {
+#ifdef LWIP_CACHE_ENABLED
+ /**
+ * Clean the pbuf structure info. This is needed to prevent losing
+ * pbuf structure info when we invalidate the pbuf on rx interrupt
+ */
+ CacheDataCleanBuff((u32_t)(p), (u32_t)(SIZEOF_STRUCT_PBUF));
+#endif
+ curr_bd->bufptr = (u32_t)(p->payload);
+ curr_bd->bufoff_len = p->len;
+ curr_bd->flags_pktlen = CPDMA_BUF_DESC_OWNER;
+
+ /* Save the pbuf */
+ curr_bd->pbuf = p;
+ last_bd = curr_bd;
+ curr_bd = curr_bd->next;
+ rxch->free_num--;
+ } else {
+ break;
+ }
+ }
+
+ if(saved_free_num == rxch->free_num) {
+ /* No bd's were allocated. Go back. */
+ return;
+ }
+
+ rxch->recv_tail = last_bd;
+
+ /**
+ * If the entire ring is traversed, curr_bd will be NULL. In that case,
+ * write the Rx HDP in order to continue reception
+ */
+ if(NULL != curr_bd) {
+ rxch->free_head = curr_bd;
+ } else {
+ CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, (u32_t)(recv_head), 0);
+ }
+
+ recv_tail->next = recv_head;
+
+ /* Close the ring to prevent overwriting of pbuf data */
+ last_bd->next = NULL;
+
+ /**
+ * Check if the reception has ended. If the EOQ flag is set, the NULL
+ * Pointer is already taken by the DMA engine. So we need to write the
+ * RX HDP with the next descriptor.
+ */
+ if(recv_tail->flags_pktlen & CPDMA_BUF_DESC_EOQ) {
+ CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, (u32_t)(recv_head), 0);
+ }
+}
+
+/**
+ * This function does the actual transmission of the packet. The packet is
+ * contained in the pbuf that is passed to the function. This pbuf might be
+ * chained. That is, one pbuf can span more than one tx buffer descriptors
+ *
+ * @param netif the network interface state for this ethernetif
+ * @param pbuf the pbuf which is to be sent over EMAC
+ * @return status ERR_OK, if transmit was successful
+ * ERR_MEM, if no memory available
+ */
+static err_t
+cpswif_transmit(struct netif *netif, struct pbuf *pbuf) {
+ struct pbuf *q;
+ struct txch *txch;
+ volatile struct cpdma_tx_bd *curr_bd, *bd_to_send, *bd_end;
+ struct cpswportif *cpswif = netif->state;
+ u32_t inst_num = cpswif->inst_num;
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+
+#ifdef CPSW_DUAL_MAC_MODE
+ u32_t port_num = cpswif->port_num;
+#endif
+
+ txch = &(cpswinst->txch);
+
+ /* Do not send if there are no enough free bd's */
+ if(pbuf_clen(pbuf) > txch->free_num) {
+ return ERR_MEM;
+ }
+
+ /* Get the buffer descriptor which is free to transmit */
+ curr_bd = txch->free_head;
+
+ bd_to_send = txch->free_head;
+
+ /* Update the total packet length */
+ curr_bd->flags_pktlen = pbuf->tot_len;
+
+ /* Indicate the start of the packet */
+ curr_bd->flags_pktlen |= (CPDMA_BUF_DESC_SOP | CPDMA_BUF_DESC_OWNER);
+
+#ifdef CPSW_DUAL_MAC_MODE
+ /* Indicate to which port the packet has to be sent */
+ curr_bd->flags_pktlen |= CPDMA_BUF_DESC_TO_PORT(port_num);
+#endif
+
+ /* Copy pbuf information into TX buffer descriptors */
+ for(q = pbuf; q != NULL; q = q->next) {
+#ifdef LWIP_CACHE_ENABLED
+ /**
+ * Make sure that the payload is written to memory. Clean
+ * the portion of cache to make it coherent with the memory.
+ */
+ CacheDataCleanBuff((u32_t)(q->payload), (u32_t)(q->len));
+#endif
+ /* Intialize the buffer pointer and length */
+ curr_bd->bufptr = (u32_t)(q->payload);
+ curr_bd->bufoff_len = (q->len) & CPDMA_BD_LEN_MASK;
+ bd_end = curr_bd;
+ curr_bd->pbuf = pbuf;
+ curr_bd = curr_bd->next;
+
+ /* Decrement free bds, since one is consumed */
+ txch->free_num--;
+ }
+ /* Indicate the end of the packet */
+ bd_end->next = NULL;
+ bd_end->flags_pktlen |= CPDMA_BUF_DESC_EOP;
+ bd_end->flags_pktlen &= ~CPDMA_BUF_DESC_EOQ;
+
+ txch->free_head = curr_bd;
+
+ /* For the first time, write the HDP with the filled bd */
+ if(txch->send_tail == NULL) {
+ CPSWCPDMATxHdrDescPtrWrite(cpswinst->cpdma_base,
+ (u32_t)(bd_to_send), 0);
+ } else {
+ /**
+ * Chain the bd's. If the DMA engine, already reached the end of the chain,
+ * the EOQ will be set. In that case, the HDP shall be written again.
+ */
+ curr_bd = txch->send_tail;
+ curr_bd->next = bd_to_send;
+
+ if(curr_bd->flags_pktlen & CPDMA_BUF_DESC_EOQ) {
+ /* Write the Header Descriptor Pointer and start DMA */
+ CPSWCPDMATxHdrDescPtrWrite(cpswinst->cpdma_base,
+ (u32_t)(bd_to_send), 0);
+ }
+ }
+
+ txch->send_tail = bd_end;
+
+ return ERR_OK;
+}
+
+/**
+ * This function will send a packet through the emac if the channel is
+ * available. Otherwise, the packet will be queued in a pbuf queue.
+ *
+ * @param netif The lwip network interface structure for this ethernetif
+ * @param p The MAC packet to send (e.g. IP packet including
+ * MAC addresses and type)
+ * @return ERR_OK if the packet could be sent
+ * an err_t value if the packet couldn't be sent
+ *
+ */
+static err_t
+cpswif_output(struct netif *netif, struct pbuf *p) {
+ err_t stat;
+ struct pbuf *q;
+ struct cpswportif *cpswif = netif->state;
+ u32_t inst_num = cpswif->inst_num;
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ /**
+ * This entire function must run within a "critical section" to preserve
+ * the integrity of the transmit pbuf queue.
+ */
+
+ sys_mutex_lock(&cpswinst->txmtx);
+ SYS_ARCH_PROTECT(lev);
+
+ /**
+ * Adjust the packet length if less than minimum required.
+ */
+ if(p->tot_len < MIN_PKT_LEN) {
+ p->tot_len = MIN_PKT_LEN;
+
+ for(q = p; q->next != NULL; q = q->next) {
+ q->next->tot_len = q->tot_len - q->len;
+ }
+
+ /* Adjust the length of the last pbuf. (contents - don't care) */
+ q->len = q->tot_len;
+ }
+
+ /**
+ * Bump the reference count on the pbuf to prevent it from being
+ * freed till we are done with it.
+ */
+ pbuf_ref(p);
+
+ /* call the actual transmit function */
+ stat = cpswif_transmit(netif, p);
+
+ /* Return to prior interrupt state and return. */
+ SYS_ARCH_UNPROTECT(lev);
+ sys_mutex_unlock(&cpswinst->txmtx);
+
+ return stat;
+}
+
+/**
+ * Configures PHY link for a port
+ * @param cpswif The CPSW interface structure pointer
+ * @param slv_port_num The slave port number
+ *
+ * @return ERR_OK if link configurations are successful
+ * an error status if failed
+ */
+static err_t
+cpswif_phylink_config(struct cpswportif * cpswif, u32_t slv_port_num) {
+ struct cpswinst *cpswinst = &cpsw_inst_data[cpswif->inst_num];
+ err_t err;
+
+ /* Check if ethernet PHY is present or not */
+ if(0 == (MDIOPhyAliveStatusGet(cpswinst->mdio_base)
+ & (1 << cpswinst->port[slv_port_num - 1].phy_addr))){
+ LWIP_PRINTF("\n\rNo PHY found at address %d for Port %d of Instance %d.",
+ cpswinst->port[slv_port_num - 1].phy_addr, slv_port_num,
+ cpswif->inst_num);
+ return ERR_CONN;
+ }
+
+ LWIP_PRINTF("\n\rPHY found at address %d for Port %d of Instance %d.",
+ cpswinst->port[slv_port_num - 1].phy_addr, slv_port_num,
+ cpswif->inst_num);
+
+ /**
+ * PHY is alive. So autonegotiate and get the speed and duplex
+ * parameters, set it in the sliver
+ */
+ err = (err_t)(cpswif_autoneg_config(cpswif->inst_num, slv_port_num));
+
+ /* Check if PHY link is there or not */
+ if(FALSE == ((PhyLinkStatusGet(cpswinst->mdio_base,
+ cpswinst->port[slv_port_num - 1].phy_addr, 1000)))) {
+ LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Instance %d.",
+ slv_port_num, cpswif->inst_num);
+ return ERR_CONN;
+ }
+
+ LWIP_PRINTF("\n\rPHY link verified for Port %d of Instance %d.",
+ slv_port_num, cpswif->inst_num);
+
+ CPSWSlRGMIIEnable(cpswinst->port[slv_port_num - 1].sliver_base);
+
+ return err;
+}
+
+/**
+ * Initializes the CPSW port
+ * @param netif The cpsw interface
+ *
+ * @return ERR_OK if port initialization is successful
+ * an error status if failed
+ */
+static err_t
+cpswif_port_init(struct netif *netif) {
+ struct cpswportif *cpswif = (struct cpswportif*)(netif->state);
+ u32_t temp;
+ err_t err;
+
+#ifdef CPSW_DUAL_MAC_MODE
+ struct cpswinst *cpswinst = &cpsw_inst_data[cpswif->inst_num];
+ u32_t curr_port = cpswif->port_num;
+#endif
+ sem_init(&cpswinst->rxsem, SEM_DEFAULT_PSHARED, SEM_INITIAL_VALUE);
+
+ cpswinst->RxThread = sys_thread_new("receive_thread", rx_thread_function, netif, RX_THREAD_STACKSIZE, RX_PRIORITY);
+ LWIP_ASSERT("RxThread creation error", (cpswinst->RxThread));
+
+ sem_init(&cpswinst->txsem, SEM_DEFAULT_PSHARED, SEM_INITIAL_VALUE);
+
+ cpswinst->TxThread = sys_thread_new("transmit_thread", tx_thread_function, netif, TX_THREAD_STACKSIZE, TX_PRIORITY);
+ LWIP_ASSERT("TxThread creation error", (cpswinst->TxThread));
+
+ err = sys_mutex_new(&cpswinst->txmtx);
+ LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
+
+ /* set MAC hardware address length */
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* set MAC hardware address */
+ for(temp = 0; temp < ETHARP_HWADDR_LEN; temp++) {
+ netif->hwaddr[temp] = cpswif->eth_addr[temp];
+ }
+
+ /* maximum transfer unit */
+ netif->mtu = MAX_TRANSFER_UNIT;
+
+ /* device capabilities */
+ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
+
+#ifdef CPSW_DUAL_MAC_MODE
+ /* Set the ethernet address for the port */
+ CPSWPortSrcAddrSet(cpswinst->port[curr_port - 1].port_base,
+ (u8_t *)(&(cpswif->eth_addr)));
+
+ /**
+ * For Dual Mac mode, configure port0 and port1 for one VLAN ID;
+ * port0 and port2 for a different VLAN ID. Here we choose the
+ * port number as VLAN ID.
+ */
+ CPSWPortVLANConfig(cpswinst->port[curr_port - 1].port_base, curr_port, 0, 0);
+
+ cpswif_port_to_host_vlan_cfg(cpswinst, curr_port,
+ (u8_t *)(&(cpswif->eth_addr)));
+
+ err = cpswif_phylink_config(cpswif, curr_port);
+
+#else
+ err = cpswif_phylink_config(cpswif, 1);
+ err = err & (cpswif_phylink_config(cpswif, 2));
+
+#endif
+
+ return err;
+}
+
+/**
+ * This function intializes the CPDMA.
+ * The CPPI RAM will be initialized for transmit and receive
+ * buffer descriptor rings.
+ *
+ * @param cpswinst The CPSW instance structure pointer
+ * @return None
+ */
+static void
+cpswif_cpdma_init(struct cpswinst *cpswinst) {
+ u32_t num_bd;
+ volatile struct cpdma_tx_bd *curr_txbd, *last_txbd;
+ volatile struct cpdma_rx_bd *curr_rxbd, *last_rxbd;
+ struct txch *txch;
+ struct rxch *rxch;
+
+ txch = &(cpswinst->txch);
+
+ /* Initialize the CPDMA memory. Only Channel 0 is supported */
+ txch->free_head = (volatile struct cpdma_tx_bd*)(cpswinst->cppi_ram_base);
+ txch->send_head = txch->free_head;
+ txch->send_tail = NULL;
+
+ /* Allocate half of the CPPI RAM for TX buffer descriptors */
+ num_bd = (SIZE_CPPI_RAM >> 1) / sizeof(cpdma_tx_bd);
+
+ /* All buffer descriptors are free to send */
+ txch->free_num = num_bd;
+
+ curr_txbd = txch->free_head;
+
+ /* Initialize all the TX buffer descriptors ring */
+ while(num_bd) {
+ curr_txbd->next = curr_txbd + 1;
+ curr_txbd->flags_pktlen = 0;
+ last_txbd = curr_txbd;
+ curr_txbd = curr_txbd->next;
+ num_bd--;
+ }
+ last_txbd->next = txch->free_head;
+
+ /* Initialize the descriptors for the RX channel */
+ rxch = &(cpswinst->rxch);
+ rxch->free_head = (volatile struct cpdma_rx_bd*)(cpswinst->cppi_ram_base +
+ (SIZE_CPPI_RAM >> 1));
+
+ /* Allocate half of the CPPI RAM available for RX buffer dscriptors */
+ num_bd = (SIZE_CPPI_RAM >> 1) / sizeof(cpdma_rx_bd);
+ rxch->free_num = num_bd;
+
+ curr_rxbd = rxch->free_head;
+
+ /* Create the rx ring of buffer descriptors */
+ while(num_bd) {
+ curr_rxbd->next = curr_rxbd + 1;
+ curr_rxbd->flags_pktlen = CPDMA_BUF_DESC_OWNER;
+ last_rxbd = curr_rxbd;
+ curr_rxbd = curr_rxbd->next;
+ num_bd--;
+ }
+
+ last_rxbd->next = rxch->free_head;
+
+ /* We are going to receive starting from the free head */
+ rxch->recv_head = rxch->free_head;
+ rxch->recv_tail = last_rxbd;
+ cpswif_rxbd_alloc(cpswinst);
+
+ /* close the ring */
+ last_rxbd->next = NULL;
+
+ CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, (u32_t)(rxch->recv_head), 0);
+}
+
+/**
+ * In this function, the hardware should be initialized.
+ * Called from cpswif_init().
+ *
+ * @param cpswportif The CPSW port interface structure pointer
+ * @return None
+ */
+static void
+cpswif_inst_init(struct cpswportif *cpswif){
+ u32_t inst_num = cpswif->inst_num;
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+
+ /* Reset the different modules */
+ CPSWSSReset(cpswinst->ss_base);
+ CPSWWrReset(cpswinst->wrpr_base);
+ CPSWSlReset(cpswinst->port[PORT_1].sliver_base);
+ CPSWSlReset(cpswinst->port[PORT_2].sliver_base);
+ CPSWCPDMAReset(cpswinst->cpdma_base);
+
+ /* Initialize MDIO */
+ MDIOInit(cpswinst->mdio_base, MDIO_FREQ_INPUT, MDIO_FREQ_OUTPUT);
+ delay(1);
+
+ CPSWALEInit(cpswinst->ale_base);
+
+ /* Set the port 0, 1 and 2 states to FORWARD */
+ CPSWALEPortStateSet(cpswinst->ale_base, 0, CPSW_ALE_PORT_STATE_FWD);
+ CPSWALEPortStateSet(cpswinst->ale_base, 1, CPSW_ALE_PORT_STATE_FWD);
+ CPSWALEPortStateSet(cpswinst->ale_base, 2, CPSW_ALE_PORT_STATE_FWD);
+
+#ifdef CPSW_DUAL_MAC_MODE
+ /* For Dual Mac Mode, Configure for VLAN Aware Mode */
+ CPSWALEVLANAwareSet(cpswinst->ale_base);
+ CPSWHostPortDualMacModeSet(cpswinst->host_port_base);
+
+#else /*CPSW_DUAL_MAC_MODE */
+ /* For normal CPSW switch mode, set multicast entry. */
+ u8_t bcast_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ cpswif_ale_multicastentry_set(cpswinst,
+ PORT_0_MASK | PORT_1_MASK | PORT_2_MASK,
+ bcast_addr);
+ cpswif_ale_unicastentry_set(cpswinst, 0,
+ (u8_t *)(&(cpswif->eth_addr)));
+
+ /* Set the ethernet address for both the ports */
+ CPSWPortSrcAddrSet(cpswinst->port[0].port_base,
+ (u8_t *)(&(cpswif->eth_addr)));
+ CPSWPortSrcAddrSet(cpswinst->port[1].port_base,
+ (u8_t *)(&(cpswif->eth_addr)));
+
+#endif /*CPSW_DUAL_MAC_MODE */
+
+ /* Enable the statistics. Lets see in case we come across any issues */
+ CPSWStatisticsEnable(cpswinst->ss_base);
+
+ /* Initialize the buffer descriptors for CPDMA */
+ cpswif_cpdma_init(cpswinst);
+
+ /* Acknowledge receive and transmit interrupts for proper interrupt pulsing*/
+ CPSWCPDMAEndOfIntVectorWrite(cpswinst->cpdma_base, CPSW_EOI_TX_PULSE);
+ CPSWCPDMAEndOfIntVectorWrite(cpswinst->cpdma_base, CPSW_EOI_RX_PULSE);
+
+ /* Enable the transmission and reception */
+ CPSWCPDMATxEnable(cpswinst->cpdma_base);
+ CPSWCPDMARxEnable(cpswinst->cpdma_base);
+
+ /* Enable the interrupts for channel 0 and for control core 0 */
+ CPSWCPDMATxIntEnable(cpswinst->cpdma_base, 0);
+ CPSWWrCoreIntEnable(cpswinst->wrpr_base, 0, 0, CPSW_CORE_INT_TX_PULSE);
+
+ CPSWCPDMARxIntEnable(cpswinst->cpdma_base, 0);
+ CPSWWrCoreIntEnable(cpswinst->wrpr_base, 0, 0, CPSW_CORE_INT_RX_PULSE);
+}
+
+/**
+ * Should be called at the beginning of the program to set up the
+ * network interface. It calls the functions cpswif_inst_init() and
+ * cpswif_port_init() to do low level initializations
+ *
+ * @param netif The lwip network interface structure for this ethernetif
+ * @return ERR_OK If the interface is initialized
+ * any other err_t on error
+ */
+err_t
+cpswif_init(struct netif *netif)
+{
+ struct cpswportif *cpswif = (struct cpswportif*)(netif->state);
+ static u32_t inst_init_flag = 0;
+ u32_t inst_num = cpswif->inst_num;
+
+#if LWIP_NETIF_HOSTNAME
+ /* Initialize interface hostname */
+ netif->hostname = "lwip";
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ /**
+ * Initialize the snmp variables and counters inside the struct netif.
+ * The last argument should be replaced with your link speed, in units
+ * of bits per second.
+ */
+ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
+
+ /* let us use the interface number to identify netif */
+#ifdef CPSW_DUAL_MAC_MODE
+ netif->num = (u8_t)(((cpswif->inst_num * MAX_SLAVEPORT_PER_INST)
+ + cpswif->port_num - 1) & 0xFF);
+#else
+ netif->num = (u8_t)(cpswif->inst_num);
+#endif
+
+ /**
+ * We directly use etharp_output() here to save a function call.
+ * You can instead declare your own function an call etharp_output()
+ * from it if you have to do some checks before sending (e.g. if link
+ * is available...)
+ */
+ netif->output = etharp_output;
+ netif->linkoutput = cpswif_output;
+
+ /**
+ * Initialize an instance only once. Port initialization will be
+ * done separately.
+ */
+ if(((inst_init_flag >> inst_num) & 0x01) == 0) {
+ cpswif_inst_config(cpswif);
+ cpswif_inst_init(cpswif);
+ inst_init_flag |= (1 << inst_num);
+ }
+
+ if(cpswif_port_init(netif) != ERR_OK) {
+ return ERR_CONN;
+ }
+
+ return ERR_OK;
+}
+
+/**
+ * Handler for Receive interrupt. Packet processing is done in this
+ * interrupt handler itself.
+ *
+ * @param inst_num the instance for which interrupt was generated
+ * @param netif_arr the address of the array of netifs
+ * @return none
+ */
+void
+cpswif_rx_inthandler(const u32_t inst_num) {
+ struct cpswinst *const cpswinst = &cpsw_inst_data[inst_num];
+ sem_t* const rxsem = &cpswinst->rxsem;
+ const u32_t cpdma_base = cpswinst->cpdma_base;
+ unsigned int curr_bd;
+
+ sem_post(rxsem);
+
+ /* Get the bd which contains the earliest filled data */
+ curr_bd = CPSWCPDMARxCPRead(cpdma_base, 0);
+ /* Acknowledge that this packet is processed */
+ CPSWCPDMARxCPWrite(cpdma_base, 0, (unsigned int)curr_bd);
+ CPSWCPDMAEndOfIntVectorWrite(cpdma_base, CPSW_EOI_RX_PULSE);
+}
+
+static void
+process_input(const u32_t inst_num, struct netif *const netif_arr) {
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+ struct rxch *rxch;
+ volatile struct cpdma_rx_bd *curr_bd;
+ volatile struct pbuf *pbuf;
+ u32_t tot_len, if_num;
+
+#ifdef CPSW_DUAL_MAC_MODE
+ u32_t from_port;
+#endif
+
+ /* Get the rx channel pointer */
+ rxch = &(cpswinst->rxch);
+
+ /* Get the bd which contains the earliest filled data */
+ curr_bd = rxch->recv_head;
+
+ /**
+ * Process the receive buffer descriptors. When the DMA completes
+ * reception, OWNERSHIP flag will be cleared.
+ */
+ while((curr_bd->flags_pktlen & CPDMA_BUF_DESC_OWNER)
+ != CPDMA_BUF_DESC_OWNER) {
+
+#ifdef CPSW_DUAL_MAC_MODE
+ /**
+ * From which slave port the packet came from ?
+ * We will use this to decide to which netif the packet
+ * is to be forwarded to.
+ */
+ from_port = ((curr_bd->flags_pktlen) & CPDMA_BUF_DESC_FROM_PORT)
+ >> CPDMA_BUF_DESC_FROM_PORT_SHIFT;
+#endif
+
+ /* Get the total length of the packet */
+ tot_len = (curr_bd->flags_pktlen) & CPDMA_BD_PKTLEN_MASK;
+
+ /* Get the pbuf which is associated with the current bd */
+ pbuf = curr_bd->pbuf;
+#ifdef LWIP_CACHE_ENABLED
+ /**
+ * Invalidate the cache lines of the pbuf including payload. Because
+ * the memory contents got changed by DMA.
+ */
+ CacheDataInvalidateBuff((u32_t)pbuf, (PBUF_LEN_MAX + SIZEOF_STRUCT_PBUF));
+#endif
+
+ /* Update the len and tot_len fields for the pbuf in the chain */
+ pbuf->len = (u16_t)(tot_len);
+ pbuf->tot_len = (u16_t)(tot_len);
+
+ curr_bd->flags_pktlen = CPDMA_BUF_DESC_OWNER;
+
+ /* Adjust the link statistics */
+ LINK_STATS_INC(link.recv);
+
+#ifdef CPSW_DUAL_MAC_MODE
+ if_num = (inst_num * MAX_SLAVEPORT_PER_INST) + from_port - 1;
+#else
+ if_num = inst_num;
+#endif
+ struct netif * netif = netif_arr + if_num;
+ /* Process the packet */
+ if(netif->input((struct pbuf *)pbuf, netif) != ERR_OK) {
+ /* Adjust the link statistics */
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ }
+
+ curr_bd = curr_bd->next;
+
+ /* One more buffer descriptor is free now */
+ rxch->free_num++;
+
+ /**
+ * If the DMA engine took the NULL pointer, we dont have any bd to
+ * process until new bd's are allocated.
+ */
+ if(curr_bd == NULL) {
+ rxch->recv_head = rxch->free_head;
+ break;
+ }
+ rxch->recv_head = curr_bd;
+ }
+
+ /* We got some bd's freed; Allocate them */
+ cpswif_rxbd_alloc(cpswinst);
+}
+
+static void
+rx_thread_function(void* arg) {
+struct netif *const netif = arg;
+struct cpswportif * const cpswif = netif->state;
+const u32_t inst_num = cpswif->inst_num;
+struct cpswinst *const cpswinst = &cpsw_inst_data[inst_num];
+sem_t *const rxsem = &cpswinst->rxsem;
+while (1) {
+ sem_wait(rxsem);
+ process_input(inst_num, netif);
+ sched_yield();
+ }
+}
+
+/**
+ * Handler for CPSW Transmit interrupt
+ *
+ * @param netif the lwip network interface structure for this ethernetif
+ * @return none
+ */
+void
+cpswif_tx_inthandler(const u32_t inst_num) {
+ struct cpswinst *const cpswinst = &cpsw_inst_data[inst_num];
+ sem_t* const txsem = &cpswinst->txsem;
+ const u32_t cpdma_base = cpswinst->cpdma_base;
+ unsigned int curr_bd;
+
+ sem_post(txsem);
+
+ /* Get the bd which contains the earliest filled data */
+ curr_bd = CPSWCPDMATxCPRead(cpdma_base, 0);
+ /* Acknowledge that this packet is processed */
+ CPSWCPDMATxCPWrite(cpdma_base, 0, (unsigned int)curr_bd);
+ CPSWCPDMAEndOfIntVectorWrite(cpdma_base, CPSW_EOI_TX_PULSE);
+}
+
+static void process_tx_end(const u32_t inst_num)
+{
+ struct txch *txch;
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+ volatile struct cpdma_tx_bd *curr_bd, *send_head;
+ volatile u32_t cnt = 0xFFFF;
+
+ txch = &(cpswinst->txch);
+
+ send_head = txch->send_head;
+
+ curr_bd = send_head;
+
+ /* Check for correct start of packet */
+ while((curr_bd->flags_pktlen) & CPDMA_BUF_DESC_SOP) {
+
+ /* Make sure that the transmission is over */
+ while(((curr_bd->flags_pktlen & CPDMA_BUF_DESC_OWNER)
+ == CPDMA_BUF_DESC_OWNER) && ((--cnt) != 0));
+
+ /* If CPDMA failed to transmit, give it a chance once more */
+ if(0 == cnt) {
+ CPSWCPDMATxHdrDescPtrWrite(cpswinst->cpdma_base,
+ (u32_t)(curr_bd), 0);
+ return;
+ }
+
+ /* One buffer descriptor is free now */
+ txch->free_num++;
+
+ /* Traverse till the end of packet is reached */
+ while(((curr_bd->flags_pktlen) & CPDMA_BUF_DESC_EOP) != CPDMA_BUF_DESC_EOP) {
+ curr_bd = curr_bd->next;
+
+ /* As this bd is not the end, its free now */
+ txch->free_num++;
+
+ if(txch->free_num == (SIZE_CPPI_RAM >> 1) / sizeof(cpdma_tx_bd)) {
+ break;
+ }
+ }
+
+ send_head->flags_pktlen &= ~(CPDMA_BUF_DESC_SOP);
+ curr_bd->flags_pktlen &= ~(CPDMA_BUF_DESC_EOP);
+
+ /**
+ * If there are no more data transmitted, the next interrupt
+ * shall happen with the pbuf associated with the free_head
+ */
+ if(curr_bd->next == NULL) {
+ txch->send_head = txch->free_head;
+ } else {
+ txch->send_head = curr_bd->next;
+ }
+
+ pbuf_free((struct pbuf *)curr_bd->pbuf);
+
+ LINK_STATS_INC(link.xmit);
+
+ send_head = txch->send_head;
+ curr_bd = send_head;
+ }
+}
+
+static void
+tx_thread_function(void* arg) {
+struct netif * const netif = arg;
+struct cpswportif * const cpswif = netif->state;
+const u32_t inst_num = cpswif->inst_num;
+struct cpswinst *const cpswinst = &cpsw_inst_data[inst_num];
+sem_t* const txsem = &cpswinst->txsem;
+sys_mutex_t* const txmtx = &cpswinst->txmtx;
+while (1) {
+ /* Wait for receive task to wakeup */
+ sem_wait(txsem);
+ sys_mutex_lock(txmtx);
+ process_tx_end(inst_num);
+ sys_mutex_unlock(txmtx);
+ sched_yield();
+ }
+}
+
+/**
+ * Gets the netif status
+ *
+ * @param netif The netif whoes status to be checked
+ * @return The netif status
+ */
+u32_t
+cpswif_netif_status(struct netif *netif) {
+ return ((u32_t)(netif_is_up(netif)));
+}
+
+/**
+ * Returns the link status
+ *
+ * @param inst_num The instance number of the module
+ * @param slv_port_num The slave port number for the module
+ *
+ * @return the link status
+ */
+u32_t
+cpswif_link_status(u32_t inst_num, u32_t slv_port_num) {
+
+ struct cpswinst *cpswinst = &cpsw_inst_data[inst_num];
+
+ return (PhyLinkStatusGet(cpswinst->mdio_base,
+ cpswinst->port[slv_port_num - 1].phy_addr, 3));
+}
+
+/**
+ * Checks the value is in the range of min and max
+ *
+ * @param vlaue Value
+ * @param min Minimum Value
+ * @param max Maximum Value
+ *
+ * @return the status
+ */
+static u32_t
+check_valid(u32_t value, u32_t min, u32_t max) {
+ if ((min <= value) && (value <= max))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*
+ * Executes following CPSW Configutarions
+ * Switch Configuration (CPSW_SWITCH_CONFIG has to be defined)
+ * 1 - Add a multicast entry
+ * 2 - Add a unicast entry
+ * 3 - Add a OUI entry
+ * 4 - Search address in entry list
+ * 5 - Delete a multicast entry
+ * 6 - Delete a unicast entry
+ * 7 - Adds a vlan entry
+ * 8 - Search vlan in entry list
+ * 9 - Delete vlan
+ * 10 - Configure Port Vlan (ID, CFI, PRI)
+ * 11 - Age Out the Untouched entries of ALE Table
+ * 12 - Print Dump of Switch
+ * 13 - Print Dump of Switch Config
+ * 14 - ALE VLAN Aware Config
+ * 15 - Configure Rate Limit for TX or RX
+ * 16 - Enable Engress Check
+ * 17 - Set port unknown VLAN info
+ * 18 - Enable MAC Auth
+ * 19 - Configure Port State
+ * Phy Configuration
+ * 1 - Configure PHY of a port
+ *
+ * @param cpsw_switch_config parameters required for configuration
+ *
+ * @return None
+*/
+void
+cpsw_switch_configuration(struct cpsw_config *cpsw_config) {
+ struct cpswinst *cpswinst = &cpsw_inst_data[cpsw_config->cpsw_inst];
+ struct cpsw_phy_param *cpsw_phy_param = cpsw_config->phy_param;
+#ifdef CPSW_SWITCH_CONFIG
+ struct cpsw_switch_param *cpsw_switch_param = cpsw_config->switch_param;
+ s32_t ret;
+#endif /* CPSW_SWITCH_CONFIG */
+
+ switch (cpsw_config->cmd) {
+#ifdef CPSW_SWITCH_CONFIG
+ case CONFIG_SWITCH_ADD_MULTICAST:
+ {
+ if (!check_valid_addr(cpsw_switch_param->addr, ADDR_TYPE_MULTICAST)) {
+ cpsw_config->ret = ERR_ADDR;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_mask, MIN_PORT_MASK,
+ MAX_PORT_MASK)) {
+ cpsw_config->ret = ERR_PORT_MASK;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->super, MIN_SUPER, MAX_SUPER)) {
+ cpsw_config->ret = ERR_SUPER;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->fwd_state, MIN_MCAST_FWD_STATE,
+ MAX_MCAST_FWD_STATE)) {
+ cpsw_config->ret = ERR_MCAST_FWD_STATE;
+ break;
+ }
+
+ if (cpsw_switch_param->vid == 0)
+ ret = cpswif_ale_multicastentry_add(cpswinst,
+ cpsw_switch_param->port_mask,
+ cpsw_switch_param->addr,
+ cpsw_switch_param->super,
+ cpsw_switch_param->fwd_state);
+ else
+ ret = cpswif_ale_vlan_add_mcast(cpswinst, cpsw_switch_param->vid,
+ cpsw_switch_param->port_mask,
+ cpsw_switch_param->addr,
+ cpsw_switch_param->super,
+ cpsw_switch_param->fwd_state);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_ADD_UNICAST:
+ {
+ if (!check_valid_addr(cpsw_switch_param->addr, ADDR_TYPE_UNICAST)) {
+ cpsw_config->ret = ERR_ADDR;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->ucast_flags, MIN_UCAST_FLAGS,
+ MAX_UCAST_FLAGS)) {
+ cpsw_config->ret = ERR_UCAST_FLAGS;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->ucast_type, MIN_UCAST_FLAGS,
+ MAX_UCAST_FLAGS)) {
+ cpsw_config->ret = ERR_UCAST_FLAGS;
+ break;
+ }
+
+ if (cpsw_switch_param->vid == 0)
+ ret = cpswif_ale_unicastentry_add(cpswinst, cpsw_switch_param->port_num,
+ cpsw_switch_param->addr,
+ cpsw_switch_param->ucast_flags,
+ cpsw_switch_param->ucast_type);
+ else
+ ret = cpswif_ale_vlan_add_ucast(cpswinst, cpsw_switch_param->vid,
+ cpsw_switch_param->port_num,
+ cpsw_switch_param->addr,
+ cpsw_switch_param->ucast_flags,
+ cpsw_switch_param->ucast_type);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_ADD_OUI:
+ {
+ if (!check_valid_addr(cpsw_switch_param->addr, ADDR_TYPE_UNICAST)) {
+ cpsw_config->ret = ERR_ADDR;
+ break;
+ }
+
+ ret = cpswif_ale_OUI_add(cpswinst, cpsw_switch_param->addr);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_FIND_ADDR:
+ {
+ if (!check_valid_addr(cpsw_switch_param->addr, 0)) {
+ cpsw_config->ret = ERR_ADDR;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ ret = cpswif_ale_entry_match_addr(cpswinst, cpsw_switch_param->addr,
+ cpsw_switch_param->vid);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_DEL_MULTICAST:
+ {
+ if (!check_valid_addr(cpsw_switch_param->addr, ADDR_TYPE_MULTICAST)) {
+ cpsw_config->ret = ERR_ADDR;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_mask, MIN_PORT_MASK,
+ MAX_PORT_MASK)) {
+ cpsw_config->ret = ERR_PORT_MASK;
+ break;
+ }
+
+ if (cpsw_switch_param->vid == 0)
+ ret = cpswif_ale_multicastentry_del(cpswinst, cpsw_switch_param->port_mask,
+ cpsw_switch_param->addr);
+ else
+ ret = cpswif_ale_vlan_del_mcast(cpswinst, cpsw_switch_param->vid,
+ cpsw_switch_param->port_mask,
+ cpsw_switch_param->addr);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_DEL_UNICAST:
+ {
+ if (!check_valid_addr(cpsw_switch_param->addr, ADDR_TYPE_UNICAST)) {
+ cpsw_config->ret = ERR_ADDR;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ if (cpsw_switch_param->vid == 0)
+ ret = cpswif_ale_unicastentry_del(cpswinst, cpsw_switch_param->port_num,
+ cpsw_switch_param->addr);
+ else
+ ret = cpswif_ale_vlan_del_ucast(cpswinst, cpsw_switch_param->vid,
+ cpsw_switch_param->port_num,
+ cpsw_switch_param->addr);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_ADD_VLAN:
+ {
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->reg_multi, MIN_VLAN_MCAST_REG,
+ MAX_VLAN_MCAST_REG)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_REG;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->unreg_multi, MIN_VLAN_MCAST_UNREG,
+ MAX_VLAN_MCAST_UNREG)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_UNREG;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->untag_port, MIN_VLAN_UNTAG,
+ MAX_VLAN_UNTAG)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_UNTAG;
+ break;
+ }
+
+ ret = cpswif_ale_vlan_add(cpswinst, cpsw_switch_param->vid,
+ cpsw_switch_param->port_num,
+ cpsw_switch_param->untag_port,
+ cpsw_switch_param->reg_multi,
+ cpsw_switch_param->unreg_multi);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_FIND_VLAN:
+ {
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ ret = cpswif_ale_entry_match_vlan(cpswinst, cpsw_switch_param->vid);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_DEL_VLAN:
+ {
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ ret = cpswif_ale_vlan_del(cpswinst, cpsw_switch_param->vid,
+ cpsw_switch_param->port_num);
+
+ if (ret == ERR_VAL)
+ cpsw_config->ret = ERR_FAIL;
+ else
+ cpsw_config->ret = ret;
+
+ break;
+ }
+
+ case CONFIG_SWITCH_PORT_VLAN_CONFIG:
+ {
+ if (!check_valid(cpsw_switch_param->vid, MIN_VLANID, MAX_VLANID)) {
+ cpsw_config->ret = ERR_VLANID;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->cfi_port, MIN_CFI, MAX_CFI)) {
+ cpsw_config->ret = ERR_CFI;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->prio_port, MIN_PRI, MAX_PRI)) {
+ cpsw_config->ret = ERR_PRI;
+ break;
+ }
+
+ if (cpsw_switch_param->port_num == 0)
+ CPSWPortVLANConfig(cpswinst->host_port_base, cpsw_switch_param->vid,
+ cpsw_switch_param->cfi_port,
+ cpsw_switch_param->prio_port);
+ else if (cpsw_switch_param->port_num <= 2)
+ CPSWPortVLANConfig(
+ cpswinst->port[cpsw_switch_param->port_num - 1].port_base,
+ cpsw_switch_param->vid,
+ cpsw_switch_param->cfi_port,
+ cpsw_switch_param->prio_port);
+
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_AGEOUT:
+ {
+ CPSWALEAgeOut(cpswinst->ale_base);
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_DUMP:
+ {
+ u32_t cnt = 0;
+
+ for(cnt = 0; cnt <= MAX_ALE_ENTRIES; cnt++)
+ {
+ CPSWALETableEntryGet(cpswinst->ale_base, cnt,
+ cpsw_config->buf[cnt]);
+ }
+
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_CONFIG_DUMP:
+ {
+
+ if (!check_valid(cpsw_switch_param->ale_tbl_index, MIN_ALE_ENTRY_IDX,
+ MAX_ALE_ENTRY_IDX)) {
+ cpsw_config->ret = ERR_ALE_ENTRY_IDX;
+ break;
+ }
+
+ CPSWALETableEntryGet(cpswinst->ale_base, cpsw_switch_param->ale_tbl_index,
+ cpsw_config->ale_entry);
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_VLANAWARE:
+ {
+ if (!check_valid(cpsw_switch_param->vlan_aware, MIN_VLANAWARE,
+ MAX_VLANAWARE)) {
+ cpsw_config->ret = ERR_VLANAWARE;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->drop_packet, MIN_ALE_VLANAWARE,
+ MAX_ALE_VLANAWARE)) {
+ cpsw_config->ret = ERR_ALE_VLANAWARE;
+ break;
+ }
+
+ if (!cpsw_switch_param->vlan_aware)
+ CPSWVLANAwareDisable(cpswinst->ale_base);
+ else
+ CPSWVLANAwareEnable(cpswinst->ale_base);
+
+ if (!cpsw_switch_param->drop_packet)
+ CPSWALEVLANAwareClear(cpswinst->ale_base);
+ else
+ CPSWALEVLANAwareSet(cpswinst->ale_base);
+
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_RATELIMIT:
+ {
+ if (!check_valid(cpsw_switch_param->enable, MIN_ENABLE, MAX_ENABLE)) {
+ cpsw_config->ret = ERR_ENABLE;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->direction, MIN_DIRECTION,
+ MAX_DIRECTION)) {
+ cpsw_config->ret = ERR_DIRECTION;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->addr_type, MIN_ADDR_TYPE, MAX_ADDR_TYPE)) {
+ cpsw_config->ret = ERR_ADDR_TYPE;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->limit, MIN_LIMIT, MAX_LIMIT)) {
+ cpsw_config->ret = ERR_LIMIT;
+ break;
+ }
+
+ cpswif_rate_limit(cpswinst, cpsw_switch_param->enable,
+ cpsw_switch_param->direction,
+ cpsw_switch_param->port_num, cpsw_switch_param->addr_type,
+ cpsw_switch_param->limit);
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_VID_INGRESS_CHECK:
+ {
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ CPSWALEVIDIngressCheckSet(cpswinst->ale_base, cpsw_switch_param->port_num);
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO:
+ {
+ if (!check_valid(cpsw_switch_param->unknown_vlan, MIN_UNKNOWN_VLAN,
+ MAX_UNKNOWN_VLAN)) {
+ cpsw_config->ret = ERR_UNKNOWN_VLAN;
+ break;
+ }
+
+ if (cpsw_switch_param->unknown_vlan == ALE_PORT_UNTAGGED_EGRESS) {
+ if (!check_valid(cpsw_switch_param->untag_port, MIN_VLAN_UNTAG,
+ MAX_VLAN_UNTAG)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_UNTAG;
+ break;
+ }
+
+ CPSWALEUnknownUntaggedEgressSet(cpswinst->ale_base,
+ cpsw_switch_param->untag_port);
+ } else if (cpsw_switch_param->unknown_vlan ==
+ ALE_PORT_UNKNOWN_REG_MCAST_FLOOD) {
+ if (!check_valid(cpsw_switch_param->reg_multi, MIN_VLAN_MCAST_REG,
+ MAX_VLAN_MCAST_REG)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_REG;
+ break;
+ }
+
+ CPSWALEUnknownRegFloodMaskSet(cpswinst->ale_base,
+ cpsw_switch_param->reg_multi);
+ } else if (cpsw_switch_param->unknown_vlan ==
+ ALE_PORT_UNKNOWN_UNREG_MCAST_FLOOD) {
+ if (!check_valid(cpsw_switch_param->unreg_multi, MIN_VLAN_MCAST_UNREG,
+ MAX_VLAN_MCAST_UNREG)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_UNREG;
+ break;
+ }
+
+ CPSWALEUnknownUnRegFloodMaskSet(cpswinst->ale_base,
+ cpsw_switch_param->unreg_multi);
+ } else if (cpsw_switch_param->unknown_vlan ==
+ ALE_PORT_UNKNOWN_VLAN_MEMBER) {
+ if (!check_valid(cpsw_switch_param->port_mask, MIN_PORT_MASK,
+ MIN_PORT_MASK)) {
+ cpsw_config->ret = ERR_VLAN_MCAST_UNREG;
+ break;
+ }
+
+ CPSWALEUnknownMemberListSet(cpswinst->ale_base,
+ cpsw_switch_param->port_mask);
+ }
+
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_MACAUTH:
+ {
+ if (!check_valid(cpsw_switch_param->mac_auth, MIN_MAC_AUTH, MAX_MAC_AUTH)) {
+ cpsw_config->ret = ERR_MAC_AUTH;
+ break;
+ }
+
+ if (!cpsw_switch_param->mac_auth)
+ CPSWALEAUTHModeClear(cpswinst->ale_base);
+ else
+ CPSWALEAUTHModeSet(cpswinst->ale_base);
+
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ case CONFIG_SWITCH_PORT_STATE:
+ {
+ if (!check_valid(cpsw_switch_param->port_num, MIN_PORT, MAX_PORT)) {
+ cpsw_config->ret = ERR_PORT;
+ break;
+ }
+
+ if (!check_valid(cpsw_switch_param->port_state, MIN_PORT_STATE,
+ MAX_PORT_STATE)) {
+ cpsw_config->ret = ERR_PORT_STATE;
+ break;
+ }
+
+ CPSWALEPortStateSet(cpswinst->ale_base, cpsw_switch_param->port_num,
+ cpsw_switch_param->port_state);
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+#endif /* CPSW_SWITCH_CONFIG */
+
+ case CONFIG_SWITCH_SET_PORT_CONFIG:
+ {
+ if (!check_valid(cpsw_phy_param->slv_port_num, MIN_SLV_PORT,
+ MAX_SLV_PORT)) {
+ cpsw_config->ret = ERR_SLV_PORT;
+ break;
+ }
+
+ if (!check_valid(cpsw_phy_param->autoneg, MIN_AUTONEG, MAX_AUTONEG)) {
+ cpsw_config->ret = ERR_AUTONEG;
+ break;
+ }
+
+ if (TRUE == cpsw_phy_param->autoneg) {
+ if (!check_valid(cpsw_phy_param->config, MIN_PHY_CONFIG,
+ MAX_PHY_CONFIG)) {
+ cpsw_config->ret = ERR_PHY_CONFIG;
+ break;
+ }
+ } else {
+ if (!check_valid(cpsw_phy_param->speed, MIN_SPEED, MAX_SPEED)) {
+ cpsw_config->ret = ERR_SPEED;
+ break;
+ }
+
+ if (!check_valid(cpsw_phy_param->duplex, MIN_DUPLEX, MAX_DUPLEX)) {
+ cpsw_config->ret = ERR_DUPLEX;
+ break;
+ }
+ }
+
+ if (cpsw_phy_param->autoneg)
+ cpswif_phy_autoneg(cpswinst, cpsw_phy_param->slv_port_num,
+ cpsw_phy_param->config);
+ else
+ cpswif_phy_forced(cpswinst, cpsw_phy_param->slv_port_num,
+ cpsw_phy_param->speed,
+ cpsw_phy_param->duplex);
+
+ cpsw_config->ret = ERR_PASS;
+ break;
+ }
+
+ default:
+ cpsw_config->ret = ERR_INVAL;
+ break;
+ }
+}
diff --git a/cpsw/src/netif/delay.c b/cpsw/src/netif/delay.c
new file mode 100644
index 0000000..0f1b2a7
--- /dev/null
+++ b/cpsw/src/netif/delay.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+void delay(unsigned int ms)
+{
+ usleep(ms*1000);
+} \ No newline at end of file
diff --git a/cpsw/src/netif/mdio.c b/cpsw/src/netif/mdio.c
new file mode 100755
index 0000000..9c6c18e
--- /dev/null
+++ b/cpsw/src/netif/mdio.c
@@ -0,0 +1,209 @@
+/**
+ * \file mdio.c
+ *
+ * \brief MDIO APIs.
+ *
+ * This file contains the device abstraction layer APIs for MDIO.
+ */
+
+/*
+* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+*/
+/*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+/* HW Macros and Peripheral Defines */
+#include "hw_types.h"
+#include "hw_mdio.h"
+
+/* Driver APIs */
+#include "mdio.h"
+
+/*******************************************************************************
+* INTERNAL MACRO DEFINITIONS
+*******************************************************************************/
+#define PHY_REG_MASK (0x1Fu)
+#define PHY_ADDR_MASK (0x1Fu)
+#define PHY_DATA_MASK (0xFFFFu)
+#define PHY_REG_SHIFT (21u)
+#define PHY_ADDR_SHIFT (16u)
+
+/*******************************************************************************
+* API FUNCTION DEFINITIONS
+*******************************************************************************/
+
+/**
+ * \brief Reads a PHY register using MDIO.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param regNum Register Number to be read.
+ * \param dataPtr Pointer where the read value shall be written.
+ *
+ * \return status of the read \n
+ * TRUE - read is successful.\n
+ * FALSE - read is not acknowledged properly.
+ *
+ **/
+unsigned int MDIOPhyRegRead(unsigned int baseAddr, unsigned int phyAddr,
+ unsigned int regNum, volatile unsigned short *dataPtr)
+{
+ /* Wait till transaction completion if any */
+ while(HWREG(baseAddr + MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ HWREG(baseAddr + MDIO_USERACCESS0)
+ = (MDIO_USERACCESS0_READ | MDIO_USERACCESS0_GO
+ |((regNum & PHY_REG_MASK) << PHY_REG_SHIFT)
+ |((phyAddr & PHY_ADDR_MASK) << PHY_ADDR_SHIFT));
+
+ /* wait for command completion */
+ while(HWREG(baseAddr + MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ /* Store the data if the read is acknowledged */
+ if((HWREG(baseAddr + MDIO_USERACCESS0)) & MDIO_USERACCESS0_ACK)
+ {
+ *dataPtr = (unsigned short)((HWREG(baseAddr + MDIO_USERACCESS0))
+ & PHY_DATA_MASK);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * \brief Writes a PHY register using MDIO.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param regNum Register Number to be read.
+ * \param RegVal Value to be written.
+ *
+ * \return None
+ *
+ **/
+void MDIOPhyRegWrite(unsigned int baseAddr, unsigned int phyAddr,
+ unsigned int regNum, unsigned short RegVal)
+{
+ /* Wait till transaction completion if any */
+ while(HWREG(baseAddr + MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ HWREG(baseAddr + MDIO_USERACCESS0)
+ = (MDIO_USERACCESS0_WRITE | MDIO_USERACCESS0_GO
+ |((regNum & PHY_REG_MASK) << PHY_REG_SHIFT)
+ |((phyAddr & PHY_ADDR_MASK) << PHY_ADDR_SHIFT)
+ | RegVal);
+
+ /* wait for command completion*/
+ while(HWREG(baseAddr + MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+}
+/**
+ * \brief Reads the alive status of all PHY connected to this MDIO.
+ * The bit correponding to the PHY address will be set if the PHY
+ * is alive.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ *
+ * \return MDIO alive register state
+ *
+ **/
+unsigned int MDIOPhyAliveStatusGet(unsigned int baseAddr)
+{
+ return (HWREG(baseAddr + MDIO_ALIVE));
+}
+
+/**
+ * \brief Reads the link status of all PHY connected to this MDIO.
+ * The bit correponding to the PHY address will be set if the PHY
+ * link is active.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ *
+ * \return MDIO link register state
+ *
+ **/
+unsigned int MDIOPhyLinkStatusGet(unsigned int baseAddr)
+{
+ return (HWREG(baseAddr + MDIO_LINK));
+}
+
+/**
+ * \brief Initializes the MDIO peripheral. This enables the MDIO state
+ * machine, uses standard pre-amble and set the clock divider value.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param mdioInputFreq The clock input to the MDIO module
+ * \param mdioOutputFreq The clock output required on the MDIO bus
+ * \return None
+ *
+ **/
+void MDIOInit(unsigned int baseAddr, unsigned int mdioInputFreq,
+ unsigned int mdioOutputFreq)
+{
+ unsigned int clkDiv = (mdioInputFreq/mdioOutputFreq) - 1;
+
+ HWREG(baseAddr + MDIO_CONTROL) = ((clkDiv & MDIO_CONTROL_CLKDIV)
+ | MDIO_CONTROL_ENABLE
+ | MDIO_CONTROL_PREAMBLE
+ | MDIO_CONTROL_FAULTENB);
+}
+
+/**
+ * \brief Saves the MDIO register context. Note that only MDIO control
+ * register context is saved here.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param contextPtr Pointer to the structure where MDIO context
+ * needs to be saved.
+ * \return None
+ *
+ **/
+void MDIOContextSave(unsigned int baseAddr, MDIOCONTEXT *contextPtr)
+{
+ contextPtr->mdioCtrl = HWREG(baseAddr + MDIO_CONTROL);
+}
+
+/**
+ * \brief Restores the MDIO register context. Note that only MDIO control
+ * register context is restored here. Hence enough delay shall be
+ * given after this API
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param contextPtr Pointer to the structure where MDIO context
+ * needs to be restored from
+ * \return None
+ *
+ **/
+void MDIOContextRestore(unsigned int baseAddr, MDIOCONTEXT *contextPtr)
+{
+ HWREG(baseAddr + MDIO_CONTROL) = contextPtr->mdioCtrl;
+}
+
+/***************************** End Of File ***********************************/
diff --git a/cpsw/src/netif/mmu.c b/cpsw/src/netif/mmu.c
new file mode 100755
index 0000000..8015541
--- /dev/null
+++ b/cpsw/src/netif/mmu.c
@@ -0,0 +1,184 @@
+/**
+ * \file mmu.c
+ *
+ * \brief APIs for configuring MMU
+ *
+ * This file contains the APIs for configuring ARMv7a MMU.
+*/
+
+/*
+* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+*/
+/*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+
+#include "mmu.h"
+#include "cp15.h"
+
+/*****************************************************************************
+** INTERNAL MACRO DEFINITIONS
+******************************************************************************/
+#define MMU_PAGETABLE_ENTRY_FAULT (0x00)
+#define MMU_PAGEBOUND_SHIFT (20)
+#define MMU_PG_SUPSECT_SIZE_SHIFT (14)
+#define MMU_PGADDR_MASK (0xFFF00000)
+#define MMU_PGTYPE_MASK (0x00040002)
+
+/*****************************************************************************
+** FUNCTION DEFINITIONS
+******************************************************************************/
+/**
+ * \brief Initializes the Page Table with fault entries and configures CP15
+ * registers required for MMU. The Page Table passed is the master
+ * page table containing 4096 words, which will be defined by the
+ * application.
+ *
+ * \param masterPt Master Page Table Base Address
+ *
+ * \return None.
+ *
+ * \Note The StarterWare support for MMU needs only master page table
+ * configuration. Only a single level paging is supported. Also, only
+ * TTB0 will be used for page table walking.
+ **/
+void MMUInit(unsigned int *masterPt)
+{
+ unsigned int idx;
+
+ /* Invalidate the TLB entries */
+ CP15TlbInvalidate();
+
+ /* Set domain access rights */
+ CP15DomainAccessClientSet();
+
+ /* Disable TEX remapping, Access Flag usage and alignment check */
+ CP15ControlFeatureDisable( CP15_CONTROL_TEXREMAP
+ | CP15_CONTROL_ACCESSFLAG
+ | CP15_CONTROL_ALIGN_CHCK
+ | CP15_CONTROL_MMU);
+
+ /* Configure the TTB Control register to use only TTB0 */
+ CP15TtbCtlTtb0Config();
+
+ /* Se the master page table with fault entries */
+ for(idx = MMU_PAGETABLE_NUM_ENTRY; idx !=0; idx--)
+ {
+ *masterPt++ = MMU_PAGETABLE_ENTRY_FAULT;
+ }
+}
+
+/**
+ * \brief Maps a specific region for Virtual Address to Physical Address
+ * conversion. This API actually updates the corresponding page table
+ * entries. The mapping for any region is such that Virtual Address
+ * = Physical Address. \n
+ * Any region can be mapped as per the attributes given. Regions
+ * can be specified with Memory Type, Inner/Outer Cache settings,
+ * Security settings and Access Permissions.
+ *
+ * \param region Memory Region to be mapped. This shall be a structure
+ * pointer of Type REGION *. The structure is detailed in
+ * mmu.h file. \n
+ *
+ * Example Configuration: \n
+ * A 512MB RAM memory region starting at address 0x80000000 can be
+ * configured as shown below. The memory is to be cacheable, with
+ * Inner Cache - Write Through Write Allocate and Outer Cache -
+ * Write Back Write Allocate attributes. \n
+ *
+ * REGION regionRam = { MMU_PGTYPE_SECTION, \n
+ * 0x80000000, \n
+ * 512, \n
+ * MMU_MEMTYPE_NORMAL_SHAREABLE
+ * (MMU_CACHE_WT_NOWA, MMU_CACHE_WB_WA),\n
+ * MMU_REGION_NON_SECURE, \n
+ * MMU_AP_PRV_RW_USR_RW, \n
+ * (unsigned int*)pageTable};
+ *
+ * \return None.
+ *
+ * \Note The regions specify the desired cache policies. However, enabling
+ * of cache at all desired levels shall be done separately.
+ **/
+void MMUMemRegionMap(REGION *region)
+{
+ unsigned int *ptEntryPtr;
+ unsigned int ptEntry;
+ int idx;
+
+ /* Get the first entry in the page table to set */
+ ptEntryPtr = region->masterPtPtr +
+ (region->startAddr >> MMU_PAGEBOUND_SHIFT);
+
+ /* Set the pointer to the last entry */
+ ptEntryPtr += (region->numPages - 1);
+
+ /* Get the start Address MSB 3 nibbles. Ignore extended address */
+ ptEntry = (region->startAddr & region->pgType) & MMU_PGADDR_MASK;
+
+ /*
+ ** Update the page table entry with memory attributes and
+ ** Access Permissions and Security.
+ ** All the regions will be marked as global.
+ */
+ ptEntry |= ((MMU_PGTYPE_MASK & region->pgType)
+ | region->accsCtrl | region->memAttrib
+ | region->secureType);
+
+ /* Set the entries in the page table for the region attributes */
+ for(idx = (region->numPages - 1); idx >= 0; idx--)
+ {
+ *ptEntryPtr-- = ptEntry + (idx << MMU_PAGEBOUND_SHIFT) ;
+ }
+}
+
+/**
+ * \brief Updates the Translation Table Base with the address of Master Page
+ * Table and enables MMU.
+ *
+ * \param masterPt Master Page Table Base Address
+ *
+ * \return None.
+ *
+ * \Note Only TTB0 is used for page table walking.
+ **/
+void MMUEnable(unsigned int *masterPt)
+{
+ /* Set TTB0 register */
+ CP15Ttb0Set((unsigned int)masterPt);
+
+ /* Enable MMU */
+ CP15MMUEnable();
+}
+
+/***************************** End Of File ***********************************/
+
diff --git a/cpsw/src/netif/phy.c b/cpsw/src/netif/phy.c
new file mode 100755
index 0000000..1ce9494
--- /dev/null
+++ b/cpsw/src/netif/phy.c
@@ -0,0 +1,402 @@
+/**
+ * \file phy.c
+ *
+ * \brief APIs for configuring ethernet PHYs
+ *
+ * This file contains the device abstraction APIs for ethernet PHYs.
+ */
+
+/*
+* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+*/
+/*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include "hw_types.h"
+#include "mdio.h"
+#include "phy.h"
+
+#define PHY_ADV_VAL_MASK (0x01e0)
+#define PHY_GIG_ADV_VAL_MASK (0x0300)
+
+/*******************************************************************************
+* API FUNCTION DEFINITIONS
+*******************************************************************************/
+/**
+ * \brief Reads the PHY ID.
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ *
+ * \return 32 bit PHY ID (ID1:ID2)
+ *
+ **/
+unsigned int PhyIDGet(unsigned int mdioBaseAddr, unsigned int phyAddr)
+{
+ unsigned int id = 0;
+ unsigned short data;
+
+ /* read the ID1 register */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ID1, &data);
+
+ /* update the ID1 value */
+ id = data << PHY_ID_SHIFT;
+
+ /* read the ID2 register */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ID2, &data);
+
+ /* update the ID2 value */
+ id |= data;
+
+ /* return the ID in ID1:ID2 format */
+ return id;
+}
+
+/**
+ * \brief Reads a register from the the PHY
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param regIdx Index of the register to be read
+ * \param regValAdr address where value of the register will be written
+ *
+ * \return status of the read
+ *
+ **/
+unsigned int PhyRegRead(unsigned int mdioBaseAddr, unsigned int phyAddr,
+ unsigned int regIdx, unsigned short *regValAdr)
+{
+ return (MDIOPhyRegRead(mdioBaseAddr, phyAddr, regIdx, regValAdr));
+}
+
+/**
+ * \brief Writes a register with the input
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param regIdx Index of the register to be read
+ * \param regValAdr value to be written
+ *
+ * \return None
+ *
+ **/
+void PhyRegWrite(unsigned int mdioBaseAddr, unsigned int phyAddr,
+ unsigned int regIdx, unsigned short regVal)
+{
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, regIdx, regVal);
+}
+
+/**
+ * \brief Enables Loop Back mode
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ *
+ * \return status after enabling. \n
+ * TRUE if loop back is enabled \n
+ * FALSE if not able to enable
+ *
+ **/
+unsigned int PhyLoopBackEnable(unsigned int mdioBaseAddr, unsigned int phyAddr)
+{
+ unsigned short data;
+
+ if(MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE )
+ {
+ return FALSE;
+ }
+
+ data |= PHY_LPBK_ENABLE;
+
+ /* Enable loop back */
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data);
+
+ return TRUE;
+}
+
+/**
+ * \brief Disables Loop Back mode
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ *
+ * \return status after enabling. \n
+ * TRUE if loop back is disabled \n
+ * FALSE if not able to disable
+ *
+ **/
+unsigned int PhyLoopBackDisable(unsigned int mdioBaseAddr, unsigned int phyAddr)
+{
+ unsigned short data;
+
+ if(MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE )
+ {
+ return FALSE;
+ }
+
+ data &= ~(PHY_LPBK_ENABLE);
+
+ /* Disable loop back */
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data);
+
+ return TRUE;
+}
+
+/**
+ * \brief Resets the PHY
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param speed Speed to be enabled
+ * \param duplexMode Duplex Mode
+ *
+ * \return status after configuring \n
+ * TRUE if configuration successful
+ * FALSE if configuration failed
+ *
+ **/
+unsigned int PhyReset(unsigned int mdioBaseAddr, unsigned int phyAddr)
+{
+ unsigned short data;
+
+ data = PHY_SOFTRESET;
+
+ /* Reset the phy */
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data);
+
+ /* wait till the reset bit is auto cleared */
+ while(data & PHY_SOFTRESET)
+ {
+ /* Read the reset */
+ if(MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE)
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * \brief Configures the PHY for a given speed and duplex mode.
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param speed Speed to be enabled
+ * \param duplexMode Duplex Mode
+ *
+ * \return status after configuring \n
+ * TRUE if configuration successful
+ * FALSE if configuration failed
+ *
+ **/
+unsigned int PhyConfigure(unsigned int mdioBaseAddr, unsigned int phyAddr,
+ unsigned short speed, unsigned short duplexMode)
+{
+ /* Set the configurations */
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, (speed | duplexMode));
+
+ return TRUE;
+}
+
+/**
+ * \brief This function ask the phy device to start auto negotiation.
+ *
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param advVal Autonegotiation advertisement value
+ * \param gigAdvVal Gigabit capability advertisement value
+ * advVal can take the following any OR combination of the values \n
+ * PHY_100BTX - 100BaseTX \n
+ * PHY_100BTX_FD - Full duplex capabilty for 100BaseTX \n
+ * PHY_10BT - 10BaseT \n
+ * PHY_10BT_FD - Full duplex capability for 10BaseT \n
+ * gigAdvVal can take one of the following values \n
+ * PHY_NO_1000BT - No 1000Base-T capability\n
+ * PHY_1000BT_FD - Full duplex capabilty for 1000 Base-T \n
+ * PHY_1000BT_HD - Half duplex capabilty for 1000 Base-T \n
+ * FALSE - It is passed as an argument if phy dosen't support
+ * Giga bit capability
+ *
+ * \return status after autonegotiation \n
+ * TRUE if autonegotiation started
+ * FALSE if autonegotiation not started
+ *
+ **/
+unsigned int PhyAutoNegotiate(unsigned int mdioBaseAddr, unsigned int phyAddr,
+ unsigned short *advPtr, unsigned short *gigAdvPtr)
+{
+ volatile unsigned short data;
+ volatile unsigned short anar;
+
+ if(MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE )
+ {
+ return FALSE;
+ }
+
+ data |= PHY_AUTONEG_ENABLE;
+
+ if (*gigAdvPtr != 0)
+ {
+ /* Set phy for gigabit speed */
+ data &= PHY_SPEED_MASK;
+ data |= PHY_SPEED_1000MBPS;
+ }
+
+ /* Enable Auto Negotiation */
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data);
+
+ if(MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE )
+ {
+ return FALSE;
+ }
+
+ /* Write Auto Negotiation capabilities */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_AUTONEG_ADV, &anar);
+ anar &= ~PHY_ADV_VAL_MASK;
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_AUTONEG_ADV, (anar |(*advPtr)));
+
+ /* Write Auto Negotiation Gigabyte capabilities */
+ anar = 0;
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_1000BT_CONTROL, &anar);
+ anar &= ~PHY_GIG_ADV_VAL_MASK;
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_1000BT_CONTROL,
+ (anar |(*gigAdvPtr)));
+
+ data |= PHY_AUTONEG_RESTART;
+
+ /* Start Auto Negotiation */
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data);
+
+ return TRUE;
+}
+
+/**
+ * \brief Returns the status of Auto Negotiation completion.
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ *
+ * \return Auto negotiation completion status \n
+ * TRUE if auto negotiation is completed
+ * FALSE if auto negotiation is not completed
+ **/
+unsigned int PhyAutoNegStatusGet(unsigned int mdioBaseAddr, unsigned int phyAddr)
+{
+ volatile unsigned short data;
+
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BSR, &data);
+
+ /* Auto negotiation completion status */
+ if(PHY_AUTONEG_COMPLETE == (data & (PHY_AUTONEG_STATUS)))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * \brief Reads the Link Partner Ability register of the PHY.
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param ptnerAblty Pointer to which partner ability will be written.
+ * \param gbpsPtnerAblty Pointer to which Giga bit capability will be written.
+ *
+ * gbpsPtnerAblty can take following Macros.\n
+ *
+ * TRUE - It is passed as argument if phy supports Giga bit capability.\n
+ * FALSE - It is passed as argument if phy dosen't supports Giga bit
+ * capability.\n
+ *
+ * \return status after reading \n
+ * TRUE if reading successful
+ * FALSE if reading failed
+ **/
+unsigned int PhyPartnerAbilityGet(unsigned int mdioBaseAddr,
+ unsigned int phyAddr,
+ unsigned short *ptnerAblty,
+ unsigned short *gbpsPtnerAblty)
+{
+ unsigned int status;
+
+ status = MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_LINK_PARTNER_ABLTY,
+ ptnerAblty);
+
+ if (*gbpsPtnerAblty != 0)
+ {
+ status = status | MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_1000BT_STATUS,
+ gbpsPtnerAblty);
+ }
+
+ return status;
+}
+
+/**
+ * \brief Reads the link status of the PHY.
+ *
+ * \param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param retries The number of retries before indicating down status
+ *
+ * \return link status after reading \n
+ * TRUE if link is up
+ * FALSE if link is down \n
+ *
+ * \note This reads both the basic status register of the PHY and the
+ * link register of MDIO for double check
+ **/
+unsigned int PhyLinkStatusGet(unsigned int mdioBaseAddr,
+ unsigned int phyAddr,
+ volatile unsigned int retries)
+{
+ volatile unsigned short linkStatus;
+
+ retries++;
+ while (retries)
+ {
+ /* First read the BSR of the PHY */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BSR, &linkStatus);
+
+ if(linkStatus & PHY_LINK_STATUS)
+ {
+ return TRUE;
+ }
+
+ retries--;
+ }
+
+ return FALSE;
+}
+
+/**************************** End Of File ***********************************/