Other Parts Discussed in Thread: HALCOGEN
Tool/software:
/** * @file tms570_eth_driver.c * @brief TMS570 Ethernet MAC driver * * @section License * * SPDX-License-Identifier: GPL-2.0-or-later * * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved. * * This file is part of CycloneTCP Open. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Oryx Embedded SARL (www.oryx-embedded.com) * @version 2.4.2 **/ //Switch to the appropriate trace level #define TRACE_LEVEL NIC_TRACE_LEVEL //Platform-specific dependencies #if defined(_TMS570LC43x_) #include "hl_hw_reg_access.h" #include "hl_hw_emac.h" #include "hl_hw_emac_ctrl.h" #include "hl_hw_mdio.h" #include "hl_gio.h" #include "hl_sys_vim.h" #else #include "hw_reg_access.h" #include "hw_emac.h" #include "hw_emac_ctrl.h" #include "hw_mdio.h" #include "gio.h" #include "sys_vim.h" #endif //Dependencies #include "core/net.h" #include "drivers/mac/tms570_eth_driver.h" #include "debug.h" //MDIO input clock frequency #define MDIO_INPUT_CLK 75000000 //MDIO output clock frequency #define MDIO_OUTPUT_CLK 1000000 //Byte-swapped read/write accesses to CPPI memory? #if defined(_TMS570LC43x_) #define CPPI_SWAP(x) swapInt32((uint32_t) (x)) #else #define CPPI_SWAP(x) ((uint32_t) (x)) #endif //Underlying network interface static NetInterface *nicDriverInterface; //IAR EWARM compiler? #if defined(__ICCARM__) //Transmit buffer #pragma data_alignment = 4 #pragma location = TMS570_ETH_RAM_SECTION static uint8_t txBuffer[TMS570_ETH_TX_BUFFER_COUNT][TMS570_ETH_TX_BUFFER_SIZE]; //Receive buffer #pragma data_alignment = 4 #pragma location = TMS570_ETH_RAM_SECTION static uint8_t rxBuffer[TMS570_ETH_RX_BUFFER_COUNT][TMS570_ETH_RX_BUFFER_SIZE]; //Transmit buffer descriptors #pragma data_alignment = 4 #pragma location = TMS570_ETH_RAM_CPPI_SECTION static Tms570TxBufferDesc txBufferDesc[TMS570_ETH_TX_BUFFER_COUNT]; //Receive buffer descriptors #pragma data_alignment = 4 #pragma location = TMS570_ETH_RAM_CPPI_SECTION static Tms570RxBufferDesc rxBufferDesc[TMS570_ETH_RX_BUFFER_COUNT]; //GCC compiler? #else //Transmit buffer static uint8_t txBuffer[TMS570_ETH_TX_BUFFER_COUNT][TMS570_ETH_TX_BUFFER_SIZE] __attribute__((aligned(4), __section__(TMS570_ETH_RAM_SECTION))); //Receive buffer static uint8_t rxBuffer[TMS570_ETH_RX_BUFFER_COUNT][TMS570_ETH_RX_BUFFER_SIZE] __attribute__((aligned(4), __section__(TMS570_ETH_RAM_SECTION))); //Transmit buffer descriptors static Tms570TxBufferDesc txBufferDesc[TMS570_ETH_TX_BUFFER_COUNT] __attribute__((aligned(4), __section__(TMS570_ETH_RAM_CPPI_SECTION))); //Receive buffer descriptors static Tms570RxBufferDesc rxBufferDesc[TMS570_ETH_RX_BUFFER_COUNT] __attribute__((aligned(4), __section__(TMS570_ETH_RAM_CPPI_SECTION))); #endif //Pointer to the current TX buffer descriptor static Tms570TxBufferDesc *txCurBufferDesc; //Pointer to the current RX buffer descriptor static Tms570RxBufferDesc *rxCurBufferDesc; /** * @brief TMS570 Ethernet MAC driver **/ const NicDriver tms570EthDriver = { NIC_TYPE_ETHERNET, ETH_MTU, tms570EthInit, tms570EthTick, tms570EthEnableIrq, tms570EthDisableIrq, tms570EthEventHandler, tms570EthSendPacket, tms570EthUpdateMacAddrFilter, tms570EthUpdateMacConfig, tms570EthWritePhyReg, tms570EthReadPhyReg, FALSE, TRUE, TRUE, FALSE }; /** * @brief TMS570 Ethernet MAC initialization * @param[in] interface Underlying network interface * @return Error code **/ error_t tms570EthInit(NetInterface *interface) { error_t error; uint_t channel; uint32_t temp; //Debug message TRACE_INFO("Initializing TMS570 Ethernet MAC...\r\n"); //Save underlying network interface nicDriverInterface = interface; //Select the interface mode (MII/RMII) and configure pin muxing tms570EthInitGpio(interface); //Reset the EMAC control module EMAC_CTRL_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET; //Wait for the reset to complete while((EMAC_CTRL_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0) { } //Reset the EMAC module EMAC_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET; //Wait for the reset to complete while((EMAC_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0) { } //Calculate the MDC clock divider to be used temp = (MDIO_INPUT_CLK / MDIO_OUTPUT_CLK) - 1; //Initialize MDIO interface MDIO_CONTROL_R = MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULTENB | (temp & MDIO_CONTROL_CLKDIV); //Valid Ethernet PHY or switch driver? if(interface->phyDriver != NULL) { //Ethernet PHY initialization error = interface->phyDriver->init(interface); } else if(interface->switchDriver != NULL) { //Ethernet switch initialization error = interface->switchDriver->init(interface); } else { //The interface is not properly configured error = ERROR_FAILURE; } //Any error to report? if(error) { return error; } //Clear the control registers EMAC_MACCONTROL_R = 0; EMAC_RXCONTROL_R = 0; EMAC_TXCONTROL_R = 0; //Initialize all 16 header descriptor pointer registers to 0 for(channel = EMAC_CH0; channel <= EMAC_CH7; channel++) { //TX head descriptor pointer EMAC_TXHDP_R(channel) = 0; //TX completion pointer EMAC_TXCP_R(channel) = 0; //RX head descriptor pointer EMAC_RXHDP_R(channel) = 0; //RX completion pointer EMAC_RXCP_R(channel) = 0; } //Set the upper 32 bits of the source MAC address EMAC_MACSRCADDRHI_R = interface->macAddr.b[0] | (interface->macAddr.b[1] << 8) | (interface->macAddr.b[2] << 16) | (interface->macAddr.b[3] << 24); //Set the lower 16 bits of the source MAC address EMAC_MACSRCADDRLO_R = interface->macAddr.b[4] | (interface->macAddr.b[5] << 8); //Write the channel number to the MAC index register EMAC_MACINDEX_R = EMAC_CH0; //Set the upper 32 bits of the destination MAC address EMAC_MACADDRHI_R = interface->macAddr.b[0] | (interface->macAddr.b[1] << 8) | (interface->macAddr.b[2] << 16) | (interface->macAddr.b[3] << 24); //Set the lower 16 bits of the destination MAC address temp = interface->macAddr.b[4] | (interface->macAddr.b[5] << 8); //Use the current MAC address to match incoming packet addresses EMAC_MACADDRLO_R = EMAC_MACADDRLO_VALID | EMAC_MACADDRLO_MATCHFILT | (EMAC_CH0 << EMAC_MACADDRLO_CHANNEL_SHIFT) | temp; //Be sure to program all eight MAC address registers, whether the //receive channel is to be enabled or not for(channel = EMAC_CH1; channel <= EMAC_CH7; channel++) { //Write the channel number to the MAC index register EMAC_MACINDEX_R = channel; //The MAC address is not valid EMAC_MACADDRLO_R = (channel << EMAC_MACADDRLO_CHANNEL_SHIFT); } //Clear the MAC address hash registers EMAC_MACHASH1_R = 0; EMAC_MACHASH2_R = 0; //The RX buffer offset must be initialized to zero EMAC_RXBUFFEROFFSET_R = 0; //Clear all unicast channels EMAC_RXUNICASTCLEAR_R = 0xFF; //Accept unicast frames EMAC_RXUNICASTSET_R |= (1 << EMAC_CH0); //Received CRC is transferred to memory for all channels EMAC_RXMBPENABLE_R = EMAC_RXMBPENABLE_RXPASSCRC; //Accept broadcast frames EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXBROADEN | (EMAC_CH0 << EMAC_RXMBPENABLE_RXBROADCH_SHIFT); //Accept hash matching multicast frames EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXMULTEN | (EMAC_CH0 << EMAC_RXMBPENABLE_RXMULTCH_SHIFT); //Register TX interrupt handler vimChannelMap(TMS570_ETH_TX_IRQ_CHANNEL, TMS570_ETH_TX_IRQ_CHANNEL, (t_isrFuncPTR) tms570EthTxIrqHandler); //Register RX interrupt handler vimChannelMap(TMS570_ETH_RX_IRQ_CHANNEL, TMS570_ETH_RX_IRQ_CHANNEL, (t_isrFuncPTR) tms570EthRxIrqHandler); //Clear all unused channel interrupt bits EMAC_TXINTMASKCLEAR_R = 0xFF; EMAC_RXINTMASKCLEAR_R = 0xFF; //Enable the receive and transmit channel interrupt bits EMAC_TXINTMASKSET_R = (1 << EMAC_CH0); EMAC_RXINTMASKSET_R = (1 << EMAC_CH0); //Configure TX and RX buffer descriptors tms570EthInitBufferDesc(interface); //Write the RX DMA head descriptor pointer EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc; //Enable the receive and transmit DMA controllers EMAC_TXCONTROL_R = EMAC_TXCONTROL_TXEN; EMAC_RXCONTROL_R = EMAC_RXCONTROL_RXEN; //Enable TX and RX EMAC_MACCONTROL_R = EMAC_MACCONTROL_GMIIEN; //Enable TX and RX completion interrupts EMAC_CTRL_CnTXEN_R(EMAC_CORE0) |= (1 << EMAC_CH0); EMAC_CTRL_CnRXEN_R(EMAC_CORE0) |= (1 << EMAC_CH0); //Accept any packets from the upper layer osSetEvent(&interface->nicTxEvent); //Successful initialization return NO_ERROR; } /** * @brief GPIO configuration * @param[in] interface Underlying network interface **/ __weak_func void tms570EthInitGpio(NetInterface *interface) { //LAUNCHXL2-570LC43 evaluation board? #if defined(USE_LAUNCHXL2_570LC43) //Configure PHY_INT (PA_3) as an input gioPORTA->DIR &= ~(1 << 3); gioPORTA->PSL |= (1 << 3); gioPORTA->PULDIS &= ~(1 << 3); //Configure PHY_RST (PA_4) as an output gioPORTA->DIR |= (1 << 4); gioPORTA->PDR &= ~(1 << 4); //Reset PHY transceiver gioPORTA->DCLR = (1 << 4); sleep(10); gioPORTA->DSET = (1 << 4); sleep(10); #endif } /** * @brief Initialize buffer descriptor lists * @param[in] interface Underlying network interface **/ void tms570EthInitBufferDesc(NetInterface *interface) { uint_t i; uint_t nextIndex; uint_t prevIndex; //Initialize TX buffer descriptor list for(i = 0; i < TMS570_ETH_TX_BUFFER_COUNT; i++) { //Index of the next buffer nextIndex = (i + 1) % TMS570_ETH_TX_BUFFER_COUNT; //Index of the previous buffer prevIndex = (i + TMS570_ETH_TX_BUFFER_COUNT - 1) % TMS570_ETH_TX_BUFFER_COUNT; //Next descriptor pointer txBufferDesc[i].word0 = CPPI_SWAP(NULL); //Buffer pointer txBufferDesc[i].word1 = CPPI_SWAP(txBuffer[i]); //Buffer offset and buffer length txBufferDesc[i].word2 = CPPI_SWAP(0); //Status flags and packet length txBufferDesc[i].word3 = CPPI_SWAP(0); //Form a doubly linked list txBufferDesc[i].next = &txBufferDesc[nextIndex]; txBufferDesc[i].prev = &txBufferDesc[prevIndex]; } //Point to the very first descriptor txCurBufferDesc = &txBufferDesc[0]; //Mark the end of the queue txCurBufferDesc->prev->word3 = CPPI_SWAP(EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_EOQ); //Initialize RX buffer descriptor list for(i = 0; i < TMS570_ETH_RX_BUFFER_COUNT; i++) { //Index of the next buffer nextIndex = (i + 1) % TMS570_ETH_RX_BUFFER_COUNT; //Index of the previous buffer prevIndex = (i + TMS570_ETH_RX_BUFFER_COUNT - 1) % TMS570_ETH_RX_BUFFER_COUNT; //Next descriptor pointer rxBufferDesc[i].word0 = CPPI_SWAP(&rxBufferDesc[nextIndex]); //Buffer pointer rxBufferDesc[i].word1 = CPPI_SWAP(rxBuffer[i]); //Buffer offset and buffer length rxBufferDesc[i].word2 = CPPI_SWAP(TMS570_ETH_RX_BUFFER_SIZE); //Status flags and packet length rxBufferDesc[i].word3 = CPPI_SWAP(EMAC_RX_WORD3_OWNER); //Form a doubly linked list rxBufferDesc[i].next = &rxBufferDesc[nextIndex]; rxBufferDesc[i].prev = &rxBufferDesc[prevIndex]; } //Point to the very first descriptor rxCurBufferDesc = &rxBufferDesc[0]; //Mark the end of the queue // rxCurBufferDesc->prev->word0 = CPPI_SWAP(NULL); } /** * @brief TMS570 Ethernet MAC timer handler * * This routine is periodically called by the TCP/IP stack to handle periodic * operations such as polling the link state * * @param[in] interface Underlying network interface **/ void tms570EthTick(NetInterface *interface) { //Valid Ethernet PHY or switch driver? if(interface->phyDriver != NULL) { //Handle periodic operations interface->phyDriver->tick(interface); } else if(interface->switchDriver != NULL) { //Handle periodic operations interface->switchDriver->tick(interface); } else { //Just for sanity } //Misqueued buffer condition? if(CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_OWNER) { if(EMAC_RXHDP_R(EMAC_CH0) == 0) { //The host acts on the misqueued buffer condition by writing the added //buffer descriptor address to the appropriate RX DMA head descriptor //pointer EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc; } } } /** * @brief Enable interrupts * @param[in] interface Underlying network interface **/ void tms570EthEnableIrq(NetInterface *interface) { //Enable Ethernet MAC interrupts vimEnableInterrupt(TMS570_ETH_TX_IRQ_CHANNEL, SYS_IRQ); vimEnableInterrupt(TMS570_ETH_RX_IRQ_CHANNEL, SYS_IRQ); //Valid Ethernet PHY or switch driver? if(interface->phyDriver != NULL) { //Enable Ethernet PHY interrupts interface->phyDriver->enableIrq(interface); } else if(interface->switchDriver != NULL) { //Enable Ethernet switch interrupts interface->switchDriver->enableIrq(interface); } else { //Just for sanity } } /** * @brief Disable interrupts * @param[in] interface Underlying network interface **/ void tms570EthDisableIrq(NetInterface *interface) { //Disable Ethernet MAC interrupts vimDisableInterrupt(TMS570_ETH_TX_IRQ_CHANNEL); vimDisableInterrupt(TMS570_ETH_RX_IRQ_CHANNEL); //Valid Ethernet PHY or switch driver? if(interface->phyDriver != NULL) { //Disable Ethernet PHY interrupts interface->phyDriver->disableIrq(interface); } else if(interface->switchDriver != NULL) { //Disable Ethernet switch interrupts interface->switchDriver->disableIrq(interface); } else { //Just for sanity } } /** * @brief Ethernet MAC transmit interrupt **/ #if defined(__ICCARM__) __irq __arm #else #pragma CODE_STATE(tms570EthTxIrqHandler, 32) #pragma INTERRUPT(tms570EthTxIrqHandler, IRQ) #endif void tms570EthTxIrqHandler(void) { bool_t flag; uint32_t status; uint32_t temp; Tms570TxBufferDesc *p; //Interrupt service routine prologue osEnterIsr(); //This flag will be set if a higher priority task must be woken flag = FALSE; //Read the C0TXSTAT register to determine which channels caused the interrupt status = EMAC_CTRL_C0TXSTAT_R; //Packet transmitted on channel 0? if(status & (1 << EMAC_CH0)) { //Point to the buffer descriptor p = (Tms570TxBufferDesc *) EMAC_TXCP_R(EMAC_CH0); //Read the status flags temp = CPPI_SWAP(p->word3) & (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_OWNER | EMAC_TX_WORD3_EOQ); //Misqueued buffer condition? if(temp == (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_EOQ)) { //Check whether the next descriptor pointer is non-zero if(CPPI_SWAP(p->word0) != 0) { //The host corrects the misqueued buffer condition by writing the //misqueued packet�s buffer descriptor address to the appropriate //TX DMA head descriptor pointer EMAC_TXHDP_R(EMAC_CH0) = CPPI_SWAP(p->word0); } } //Write the TX completion pointer EMAC_TXCP_R(EMAC_CH0) = (uint32_t) p; //Check whether the TX buffer is available for writing if((CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) == 0) { //Notify the TCP/IP stack that the transmitter is ready to send flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent); } } //Write the DMA end of interrupt vector EMAC_MACEOIVECTOR_R = EMAC_MACEOIVECTOR_C0TX; //Interrupt service routine epilogue osExitIsr(flag); } /** * @brief Ethernet MAC receive interrupt **/ #if defined(__ICCARM__) __irq __arm #else #pragma CODE_STATE(tms570EthRxIrqHandler, 32) #pragma INTERRUPT(tms570EthRxIrqHandler, IRQ) #endif void tms570EthRxIrqHandler(void) { bool_t flag; uint32_t status; //Interrupt service routine prologue osEnterIsr(); //This flag will be set if a higher priority task must be woken flag = FALSE; //Read the C0RXSTAT register to determine which channels caused the interrupt status = EMAC_CTRL_C0RXSTAT_R; //Packet received on channel 0? if(status & (1 << EMAC_CH0)) { //Disable RX interrupts EMAC_CTRL_CnRXEN_R(EMAC_CORE0) &= ~(1 << EMAC_CH0); //Set event flag nicDriverInterface->nicEvent = TRUE; //Notify the TCP/IP stack of the event flag |= osSetEventFromIsr(&netEvent); } //Write the DMA end of interrupt vector EMAC_MACEOIVECTOR_R = EMAC_MACEOIVECTOR_C0RX; //Interrupt service routine epilogue osExitIsr(flag); } /** * @brief TMS570 Ethernet MAC event handler * @param[in] interface Underlying network interface **/ void tms570EthEventHandler(NetInterface *interface) { error_t error; //Process all pending packets do { //Read incoming packet error = tms570EthReceivePacket(interface); //No more data in the receive buffer? } while(error != ERROR_BUFFER_EMPTY); //Re-enable RX interrupts EMAC_CTRL_CnRXEN_R(EMAC_CORE0) |= (1 << EMAC_CH0); } /** * @brief Send a packet * @param[in] interface Underlying network interface * @param[in] buffer Multi-part buffer containing the data to send * @param[in] offset Offset to the first data byte * @param[in] ancillary Additional options passed to the stack along with * the packet * @return Error code **/ error_t tms570EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary) { size_t length; uint32_t temp; //Retrieve the length of the packet length = netBufferGetLength(buffer) - offset; //Check the frame length if(length > TMS570_ETH_TX_BUFFER_SIZE) { //The transmitter can accept another packet osSetEvent(&interface->nicTxEvent); //Report an error return ERROR_INVALID_LENGTH; } //Make sure the current buffer is available for writing if(CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) { return ERROR_FAILURE; } //Mark the end of the queue with a NULL pointer txCurBufferDesc->word0 = CPPI_SWAP(NULL); //Copy user data to the transmit buffer netBufferRead((uint8_t *) CPPI_SWAP(txCurBufferDesc->word1), buffer, offset, length); //Set the length of the buffer txCurBufferDesc->word2 = CPPI_SWAP(length & EMAC_TX_WORD2_BUFFER_LENGTH); //Give the ownership of the descriptor to the DMA txCurBufferDesc->word3 = CPPI_SWAP(EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_OWNER | (length & EMAC_TX_WORD3_PACKET_LENGTH)); //Link the current descriptor to the previous descriptor txCurBufferDesc->prev->word0 = CPPI_SWAP(txCurBufferDesc); //Read the status flags of the previous descriptor temp = CPPI_SWAP(txCurBufferDesc->prev->word3) & (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_OWNER | EMAC_TX_WORD3_EOQ); //Misqueued buffer condition? if(temp == (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_EOQ)) { //Clear the misqueued buffer condition txCurBufferDesc->prev->word3 = CPPI_SWAP(0); //The host corrects the misqueued buffer condition by writing the //misqueued packet�s buffer descriptor address to the appropriate //TX DMA head descriptor pointer EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) txCurBufferDesc; } //Point to the next descriptor in the list txCurBufferDesc = txCurBufferDesc->next; //Check whether the next buffer is available for writing if((CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) == 0) { //The transmitter can accept another packet osSetEvent(&interface->nicTxEvent); } //Data successfully written return NO_ERROR; } /** * @brief Receive a packet * @param[in] interface Underlying network interface * @return Error code **/ error_t tms570EthReceivePacket(NetInterface *interface) { static uint32_t buffer[TMS570_ETH_RX_BUFFER_SIZE / 4]; error_t error; size_t n; uint32_t temp; //Current buffer available for reading? if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_OWNER) == 0) { //SOP and EOP flags should be set if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_SOP) != 0 && (CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_EOP) != 0) { //Make sure no error occurred if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_ERROR_MASK) == 0) { //Retrieve the length of the frame n = CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_PACKET_LENGTH; //Limit the number of data to read n = MIN(n, TMS570_ETH_RX_BUFFER_SIZE); //Copy data from the receive buffer osMemcpy(buffer, (uint8_t *) CPPI_SWAP(rxCurBufferDesc->word1), n); //Valid packet received error = NO_ERROR; } else { //The received packet contains an error error = ERROR_INVALID_PACKET; } } else { //The packet is not valid error = ERROR_INVALID_PACKET; } //Mark the end of the queue with a NULL pointer rxCurBufferDesc->word0 = CPPI_SWAP(NULL); //Restore the length of the buffer rxCurBufferDesc->word2 = CPPI_SWAP(TMS570_ETH_RX_BUFFER_SIZE); //Give the ownership of the descriptor back to the DMA rxCurBufferDesc->word3 = CPPI_SWAP(EMAC_RX_WORD3_OWNER); //Link the current descriptor to the previous descriptor rxCurBufferDesc->prev->word0 = CPPI_SWAP(rxCurBufferDesc); //Read the status flags of the previous descriptor temp = CPPI_SWAP(rxCurBufferDesc->prev->word3) & (EMAC_RX_WORD3_SOP | EMAC_RX_WORD3_EOP | EMAC_RX_WORD3_OWNER | EMAC_RX_WORD3_EOQ); //Misqueued buffer condition? if(temp == (EMAC_RX_WORD3_SOP | EMAC_RX_WORD3_EOP | EMAC_RX_WORD3_EOQ)) { //The host acts on the misqueued buffer condition by writing the added //buffer descriptor address to the appropriate RX DMA head descriptor //pointer EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc; } //Write the RX completion pointer EMAC_RXCP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc; //Point to the next descriptor in the list rxCurBufferDesc = rxCurBufferDesc->next; } else { //No more data in the receive buffer error = ERROR_BUFFER_EMPTY; } //Check whether a valid packet has been received if(!error) { NetRxAncillary ancillary; //Additional options can be passed to the stack along with the packet ancillary = NET_DEFAULT_RX_ANCILLARY; //Pass the packet to the upper layer nicProcessPacket(interface, (uint8_t *) buffer, n, &ancillary); } //Return status code return error; } /** * @brief Configure MAC address filtering * @param[in] interface Underlying network interface * @return Error code **/ error_t tms570EthUpdateMacAddrFilter(NetInterface *interface) { uint_t i; uint_t k; uint8_t *p; uint32_t hashTable[2]; MacFilterEntry *entry; //Debug message TRACE_DEBUG("Updating MAC filter...\r\n"); //Clear hash table hashTable[0] = 0; hashTable[1] = 0; //The MAC address filter contains the list of MAC addresses to accept //when receiving an Ethernet frame for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++) { //Point to the current entry entry = &interface->macAddrFilter[i]; //Valid entry? if(entry->refCount > 0) { //Point to the MAC address p = entry->addr.b; //Apply the hash function k = (p[0] >> 2) ^ (p[0] << 4); k ^= (p[1] >> 4) ^ (p[1] << 2); k ^= (p[2] >> 6) ^ p[2]; k ^= (p[3] >> 2) ^ (p[3] << 4); k ^= (p[4] >> 4) ^ (p[4] << 2); k ^= (p[5] >> 6) ^ p[5]; //The hash value is reduced to a 6-bit index k &= 0x3F; //Update hash table contents hashTable[k / 32] |= (1 << (k % 32)); } } //Write the hash table EMAC_MACHASH1_R = hashTable[0]; EMAC_MACHASH2_R = hashTable[1]; //Debug message TRACE_DEBUG(" MACHASH1 = %08" PRIX32 "\r\n", EMAC_MACHASH1_R); TRACE_DEBUG(" MACHASH2 = %08" PRIX32 "\r\n", EMAC_MACHASH2_R); //Successful processing return NO_ERROR; } /** * @brief Adjust MAC configuration parameters for proper operation * @param[in] interface Underlying network interface * @return Error code **/ error_t tms570EthUpdateMacConfig(NetInterface *interface) { uint32_t config; //Read MAC control register config = EMAC_MACCONTROL_R; //100BASE-TX or 10BASE-T operation mode? if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS) { config |= EMAC_MACCONTROL_RMIISPEED; } else { config &= ~EMAC_MACCONTROL_RMIISPEED; } //Half-duplex or full-duplex mode? if(interface->duplexMode == NIC_FULL_DUPLEX_MODE) { config |= EMAC_MACCONTROL_FULLDUPLEX; } else { config &= ~EMAC_MACCONTROL_FULLDUPLEX; } //Update MAC control register EMAC_MACCONTROL_R = config; //Successful processing return NO_ERROR; } /** * @brief Write PHY register * @param[in] opcode Access type (2 bits) * @param[in] phyAddr PHY address (5 bits) * @param[in] regAddr Register address (5 bits) * @param[in] data Register value **/ void tms570EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data) { uint32_t temp; //Valid opcode? if(opcode == SMI_OPCODE_WRITE) { //Set up a write operation temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE; //PHY address temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR; //Register address temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR; //Register value temp |= data & MDIO_USERACCESS0_DATA; //Start a write operation MDIO_USERACCESS0_R = temp; //Wait for the write to complete while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0) { } } else { //The MAC peripheral only supports standard Clause 22 opcodes } } /** * @brief Read PHY register * @param[in] opcode Access type (2 bits) * @param[in] phyAddr PHY address (5 bits) * @param[in] regAddr Register address (5 bits) * @return Register value **/ uint16_t tms570EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr) { uint16_t data; uint32_t temp; //Valid opcode? if(opcode == SMI_OPCODE_READ) { //Set up a read operation temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_READ; //PHY address temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR; //Register address temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR; //Start a read operation MDIO_USERACCESS0_R = temp; //Wait for the read to complete while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0) { } //Get register value data = MDIO_USERACCESS0_R & MDIO_USERACCESS0_DATA; } else { //The MAC peripheral only supports standard Clause 22 opcodes data = 0; } //Return the value of the PHY register return data; }
I need assistance converting our Ethernet driver for the TMS570LS1227 from the current implementation in tms570_eth_driver.c
and tms570_eth_driver.h
to the new APIs provided by HalCoGen in CCS.
Details:
- Current Files:
tms570_eth_driver.c
,tms570_eth_driver.h
- Target Platform: TMS570LS1227
- Current Driver: Used with CycloneTCP
Assistance Required:
- API Mapping: Help with mapping existing functions to HalCoGen APIs, including initialization, interrupt handling, and packet operations.
- Example Code: Any examples or guidelines for using the new APIs effectively.
- Documentation: Relevant references or documentation.
Thank you for your support.