openmv/lib/alif/Alif_CMSIS/Source/driver_mac.c
iabdalkader daf2bb30da misc: Restructure repo.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2025-04-13 08:28:34 +02:00

1213 lines
37 KiB
C

/* Copyright (C) 2022 Alif Semiconductor - All Rights Reserved.
* Use, distribution and modification of this code is permitted under the
* terms stated in the Alif Semiconductor Software License Agreement
*
* You should have received a copy of the Alif Semiconductor Software
* License Agreement with this file. If not, please write to:
* contact@alifsemi.com, or visit: https://alifsemi.com/license
*
*/
/**************************************************************************//**
* @file driver_mac.c
* @author Silesh C V
* @email silesh@alifsemi.com
* @version V1.0.0
* @date 22-Mar-2022
* @brief CMSIS driver for ETH MAC.
* @bug None.
* @Note None
******************************************************************************/
#include "driver_mac.h"
#include "sys_ctrl_eth.h"
static MAC_DEV MAC0 = {
.regs = (volatile MAC_REGS *) ETH_BASE,
.flags = 0,
.cb_event = NULL,
.frame_end = NULL,
.irq = (IRQn_Type) ETH_SBD_IRQ_IRQn,
.irq_priority = RTE_ETH_MAC_IRQ_PRIORITY,
};
/* area for descriptors */
static DMA_DESC dma_descs[RX_DESC_COUNT + TX_DESC_COUNT]__attribute__((section("eth_buf"))) __attribute__((aligned(16)));
static uint32_t rx_buffers[RX_DESC_COUNT][ETH_BUF_SIZE >> 2]__attribute__((section("eth_buf")));
static uint32_t tx_buffers[TX_DESC_COUNT][ETH_BUF_SIZE >> 2]__attribute__((section("eth_buf")));
#define ARM_ETH_MAC_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0) /* driver version */
/* Driver Version */
static const ARM_DRIVER_VERSION DriverVersion = {
ARM_ETH_MAC_API_VERSION,
ARM_ETH_MAC_DRV_VERSION
};
/* Driver Capabilities */
static const ARM_ETH_MAC_CAPABILITIES DriverCapabilities = {
0, /* IPv4 header checksum verified on receive */
0, /* IPv6 checksum verification supported on receive */
0, /* UDP payload checksum verified on receive */
0, /* TCP payload checksum verified on receive */
0, /* ICMP payload checksum verified on receive */
0, /* IPv4 header checksum generated on transmit */
0, /* IPv6 checksum generation supported on transmit */
0, /* UDP payload checksum generated on transmit */
0, /* TCP payload checksum generated on transmit */
0, /* ICMP payload checksum generated on transmit */
ARM_ETH_INTERFACE_RMII, /* Ethernet Media Interface type */
0, /* driver provides initial valid MAC address */
1, /* callback event \ref ARM_ETH_MAC_EVENT_RX_FRAME generated */
1, /* callback event \ref ARM_ETH_MAC_EVENT_TX_FRAME generated */
0, /* wakeup event \ref ARM_ETH_MAC_EVENT_WAKEUP generated */
0, /* Precision Timer supported */
0 /* Reserved (must be zero) */
};
/**
\fn void setup_rxdesc(MAC_DEV *dev, uint32_t desc_id)
\brief Setup a single Rx DMA descriptor.
\param[in] dev Pointer to the MAC device instance
\param[in] desc_id The descriptor id to setup
\return none.
*/
static void setup_rxdesc(MAC_DEV *dev, uint32_t desc_id)
{
DMA_DESC *desc = &dev->rx_descs[desc_id];
SCB_InvalidateDCache_by_Addr((uint32_t *)desc, sizeof(DMA_DESC));
desc->des0 = (uint32_t) LocalToGlobal(&rx_buffers[desc_id][0]);
desc->des3 = RDES3_OWN | RDES3_INT_ON_COMPLETION_EN |
RDES3_BUFFER1_VALID_ADDR;
SCB_CleanDCache_by_Addr((uint32_t *) desc, sizeof(DMA_DESC));
}
/**
\fn void init_rx_descs(MAC_DEV *dev)
\brief Initialize Rx DMA descriptors.
\param[in] dev Pointer to the MAC device instance
\return none.
*/
static void init_rx_descs(MAC_DEV *dev)
{
uint32_t i, last_rx_desc;
for (i = 0; i < RX_DESC_COUNT; i++)
setup_rxdesc(dev, i);
dev->regs->DMA_CH0_RX_BASE_ADDR = (uint32_t) LocalToGlobal(dev->rx_descs);
dev->regs->DMA_CH0_RX_RING_LEN = RX_DESC_COUNT - 1;
last_rx_desc = (uint32_t) LocalToGlobal(&(dev->rx_descs[RX_DESC_COUNT - 1]));
dev->regs->DMA_CH0_RX_END_ADDR = last_rx_desc;
}
/**
\fn void init_tx_desc (MAC_DEV *dev)
\brief Initialize Tx DMA descriptors.
\param[in] dev Pointer to the MAC device instance
\return none.
*/
static void init_tx_descs(MAC_DEV *dev)
{
uint32_t i;
for (i = 0; i < TX_DESC_COUNT; i++)
dev->tx_descs[i] = (DMA_DESC) {0, 0, 0, 0};
dev->regs->DMA_CH0_TX_BASE_ADDR = (uint32_t) LocalToGlobal(dev->tx_descs);
dev->regs->DMA_CHO_TX_RING_LEN = TX_DESC_COUNT - 1;
SCB_CleanDCache_by_Addr((uint32_t *) dev->tx_descs,
TX_DESC_COUNT * sizeof(DMA_DESC));
}
/**
\fn void init_descriptors(MAC_DEV *dev)
\brief Initialize DMA descriptors.
\param[in] dev Pointer to the MAC device instance
\return none.
*/
static void init_descriptors(MAC_DEV *dev)
{
dev->descs = dma_descs;
dev->tx_descs = (DMA_DESC *) dev->descs;
dev->rx_descs = (dev->tx_descs + TX_DESC_COUNT);
init_rx_descs(dev);
init_tx_descs(dev);
}
/**
\fn static int32_t mac_hw_init(MAC_DEV *dev)
\brief Initialize the MAC hardware.
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status.
*/
static int32_t mac_hw_init(MAC_DEV *dev)
{
uint32_t val;
uint32_t timeout = 100;
#ifdef MTL_HAS_MULTIPLE_QUEUES
uint32_t tx_fifo_sz, rx_fifo_sz, tqs, rqs;
#endif
/* Soft reset the logic */
dev->regs->DMA_BUS_MODE |= DMA_BUS_MODE_SFT_RESET;
do {
osDelay(1);
timeout--;
} while ((dev->regs->DMA_BUS_MODE & DMA_BUS_MODE_SFT_RESET) && timeout);
if (!timeout)
return ARM_DRIVER_ERROR;
/* Configure MTL Tx Q0 Operating mode */
dev->regs->MTL_TXQ0_OP_MODE &= ~MTL_OP_MODE_TXQEN_MASK;
dev->regs->MTL_TXQ0_OP_MODE |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TSF;
/* Configure MTL RX Q0 operating mode */
dev->regs->MTL_RXQ0_OP_MODE |= (MTL_OP_MODE_RSF |
MTL_OP_MODE_FEP |
MTL_OP_MODE_FUP);
#ifdef MTL_HAS_MULTIPLE_QUEUES
/*
* configure the MTL T/Rx Q0 sizes by finding out the configured
* Tx RX FIFO sizes. Note that this is not needed if the IP is
* configured to have only one queue (each for Tx and Rx).
*/
val = dev->regs->MAC_HW_FEATURE_1;
tx_fifo_sz = (val >> MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT) &
MAC_HW_FEATURE1_TXFIFOSIZE_MASK;
rx_fifo_sz = (val >> MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT) &
MAC_HW_FEATURE1_RXFIFOSIZE_MASK;
/*
* FIFO sizes are encoded as log2(fifo_size) - 7 in the above field
* and tqs and rqs needs to be programmed in blocks of 256 bytes.
*/
tqs = (128 << tx_fifo_sz) / 256 - 1;
rqs = (128 << rx_fifo_sz) / 256 - 1;
dev->regs->MTL_TXQ0_OP_MODE &= ~(MTL_TXQ0_OPERATION_MODE_TQS_MASK <<
MTL_TXQ0_OPERATION_MODE_TQS_SHIFT);
dev->regs->MTL_TXQ0_OP_MODE |= (tqs << MTL_TXQ0_OPERATION_MODE_TQS_SHIFT);
dev->regs->MTL_RXQ0_OP_MODE &= ~(MTL_RXQ0_OPERATION_MODE_RQS_MASK <<
MTL_TXQ0_OPERATION_MODE_TQS_SHIFT);
dev->regs->MTL_RXQ0_OP_MODE |= (rqs << MTL_TXQ0_OPERATION_MODE_TQS_SHIFT);
#endif
/* Enable MAC RXQ */
dev->regs->MAC_RXQ_CTRL_0 &= ~(MAC_RXQ_CTRL0_RXQ0EN_MASK <<
MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
dev->regs->MAC_RXQ_CTRL_0 |= (MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB <<
MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
/* Configure RXQ control1 for routing multicast/broadcast queues
* Note that by default, Q0 will be used.
*/
dev->regs->MAC_RXQ_CTRL_1 |= MAC_RXQCTRL_MCBCQEN;
/* Configure tx and rx flow control */
dev->regs->MAC_Q0_TX_FLOW_CTRL |= 0xffff << MAC_Q0_TX_FLOW_CTRL_PT_SHIFT |
MAC_Q0_TX_FLOW_CTRL_TFE;
dev->regs->MAC_RX_FLOW_CTRL |= MAC_RX_FLOW_CTRL_RFE;
dev->regs->MAC_CONFIG &= ~MAC_CONFIG_JE;
dev->regs->MAC_CONFIG |= (MAC_CONFIG_FES | MAC_CONFIG_DM);
dev->regs->MAC_PACKET_FILTER |= MAC_PACKET_FILTER_PM;
/* Configure the DMA block */
dev->regs->DMA_CH0_TX_CTRL |= (16 << DMA_CH0_TX_CONTROL_TXPBL_SHIFT);
dev->regs->DMA_CH0_RX_CTRL |= ((16 << DMA_CH0_RX_CONTROL_RXPBL_SHIFT) |
(2048 << DMA_CH0_RX_CONTROL_RBSZ_SHIFT));
val = dev->regs->DMA_SYS_BUS_MODE;
val |= DMA_SYSBUS_MODE_BLEN4 | DMA_SYSBUS_MODE_BLEN8 |
DMA_SYSBUS_MODE_BLEN16;
val |= 3 << DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT;
val |= 1 << DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT;
val |= DMA_SYSBUS_MODE_ONEKBBE;
dev->regs->DMA_SYS_BUS_MODE = val;
init_descriptors(dev);
/* Enable DMA Channel 0 interrupts, rx and tx */
dev->regs->DMA_CH0_INT_ENABLE |= (DMA_CHAN_INTR_ENA_RIE |
DMA_CHAN_INTR_ENA_NIE |
DMA_CHAN_INTR_ENA_TIE);
dev->regs->DMA_CH0_TX_CTRL |= DMA_CH0_TX_CONTROL_ST;
dev->regs->DMA_CH0_RX_CTRL |= DMA_CH0_RX_CONTROL_SR;
dev->regs->MAC_CONFIG |= (MAC_CONFIG_RE | MAC_CONFIG_TE);
return 0;
}
/**
\fn uint32_t crc32_8bit_rev (uint32_t crc32, uint8_t val)
\brief Calculate 32-bit CRC (Polynom: 0x04C11DB7, data bit-reversed).
\param[in] crc32 CRC initial value
\param[in] val Input value
\return Calculated CRC value
*/
static uint32_t crc32_8bit_rev (uint32_t crc32, uint8_t val)
{
uint32_t n;
crc32 ^= __RBIT (val);
for (n = 8; n; n--) {
if (crc32 & 0x80000000) {
crc32 <<= 1;
crc32 ^= 0x04C11DB7;
} else {
crc32 <<= 1;
}
}
return crc32;
}
/**
\fn uint32_t crc32_data (const uint8_t *data, uint32_t len)
\brief Calculate standard 32-bit Ethernet CRC.
\param[in] data Pointer to buffer containing the data
\param[in] len Data length in bytes
\return Calculated CRC value
*/
static uint32_t crc32_data (const uint8_t *data, uint32_t len)
{
uint32_t crc;
for (crc = 0xFFFFFFFF; len; len--) {
crc = crc32_8bit_rev (crc, *data++);
}
return (crc ^ 0xFFFFFFFF);
}
/* Ethernet Driver functions */
/**
\fn ARM_DRIVER_VERSION GetVersion (void)
\brief Get driver version.
\return \ref ARM_DRIVER_VERSION
*/
static ARM_DRIVER_VERSION ETH_MAC_GetVersion(void)
{
return DriverVersion;
}
/**
\fn ARM_ETH_MAC_CAPABILITIES GetCapabilities (void)
\brief Get driver capabilities.
\return \ref ARM_ETH_MAC_CAPABILITIES
*/
static ARM_ETH_MAC_CAPABILITIES ETH_MAC_GetCapabilities(void)
{
return DriverCapabilities;
}
/**
\fn int32_t Initialize (ARM_ETH_MAC_SignalEvent_t cb_event, MAC_DEV *dev)
\brief Initialize Ethernet MAC Device.
\param[in] cb_event Pointer to \ref ARM_ETH_MAC_SignalEvent
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t Initialize(ARM_ETH_MAC_SignalEvent_t cb_event, MAC_DEV *dev)
{
if (!cb_event)
return ARM_DRIVER_ERROR_PARAMETER;
dev->flags |= ETH_INIT;
dev->cb_event = cb_event;
return ARM_DRIVER_OK;
}
/**
\fn int32_t Uninitialize (MAC_DEV *dev)
\brief De-initialize Ethernet MAC Device.
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t Uninitialize(MAC_DEV *dev)
{
dev->flags &= ~ETH_INIT;
return ARM_DRIVER_OK;
}
/**
\fn int32_t PowerControl (ARM_POWER_STATE state, MAC_DEV *dev)
\brief Control Ethernet MAC Device Power.
\param[in] state Power state
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t PowerControl(ARM_POWER_STATE state, MAC_DEV *dev)
{
int32_t ret, val;
switch (state) {
case ARM_POWER_OFF:
/* Disable Ethernet peripheral clock */
disable_eth_periph_clk();
NVIC_DisableIRQ(dev->irq);
dev->flags &= ~ETH_POWER;
break;
case ARM_POWER_LOW:
break;
case ARM_POWER_FULL:
if (!(dev->flags & ETH_INIT))
return ARM_DRIVER_ERROR;
if (dev->flags & ETH_POWER)
return ARM_DRIVER_OK;
/* Enable Ethernet peripheral clock */
enable_eth_periph_clk();
ret = mac_hw_init(dev);
if (ret < 0)
return ARM_DRIVER_ERROR;
NVIC_ClearPendingIRQ(dev->irq);
NVIC_SetPriority(dev->irq, dev->irq_priority);
NVIC_EnableIRQ(dev->irq);
dev->flags |= ETH_POWER;
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t GetMacAddress (ARM_ETH_MAC_ADDR *ptr_addr, MAC_DEV *dev)
\brief Get Ethernet MAC Address.
\param[in] ptr_addr Pointer to address
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t GetMacAddress(ARM_ETH_MAC_ADDR *ptr_addr, MAC_DEV *dev)
{
uint32_t hi, lo;
if (!ptr_addr)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
lo = dev->regs->MAC_ADDR_LOW_0;
hi = dev->regs->MAC_ADDR_HIGH_0 & 0xFFFF;
ptr_addr->b[0] = (lo >> 0) & 0xff;
ptr_addr->b[1] = (lo >> 8) & 0xff;
ptr_addr->b[2] = (lo >> 16) & 0xff;
ptr_addr->b[3] = (lo >> 24) & 0xff;
ptr_addr->b[4] = (hi >> 0) & 0xff;
ptr_addr->b[5] = (hi >> 8) & 0xff;
return ARM_DRIVER_OK;
}
/**
\fn int32_t SetMacAddress (const ARM_ETH_MAC_ADDR *ptr_addr, MAC_DEV *dev)
\brief Set Ethernet MAC Address.
\param[in] ptr_addr Pointer to address
\param[in] dev Pointer to MAC device instance
\return \ref execution_status
*/
static int32_t SetMacAddress(const ARM_ETH_MAC_ADDR *ptr_addr, MAC_DEV *dev)
{
uint32_t hi, lo;
if (!ptr_addr)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
hi = ((ptr_addr->b[5] << 8) | ptr_addr->b[4]) | MAC_ADDR_HIGH_AE;
lo = (ptr_addr->b[3] << 24) | (ptr_addr->b[2] << 16) |
(ptr_addr->b[1] << 8) | ptr_addr->b[0];
dev->regs->MAC_ADDR_LOW_0 = lo;
dev->regs->MAC_ADDR_HIGH_0 = hi;
return ARM_DRIVER_OK;
}
/**
\fn int32_t SetAddressFilter (const ARM_ETH_MAC_ADDR *ptr_addr,
uint32_t num_addr)
\brief Configure Address Filter.
\param[in] ptr_addr Pointer to addresses
\param[in] num_addr Number of addresses to configure
\param[in] dev Pointer to MAC device instance
\return \ref execution_status
*/
static int32_t SetAddressFilter(const ARM_ETH_MAC_ADDR *ptr_addr, uint32_t num_addr,
MAC_DEV *dev)
{
uint32_t crc;
if (!ptr_addr)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
dev->regs->MAC_PACKET_FILTER &= ~(MAC_PACKET_FILTER_HPF | MAC_PACKET_FILTER_HMC);
dev->regs->MAC_HASH_TAB_0 = 0x0;
dev->regs->MAC_HASH_TAB_1 = 0x0;
if (num_addr == 0) {
return ARM_DRIVER_OK;
}
/* Calculate 64-bit Hash table for MAC addresses */
for ( ; num_addr; ptr_addr++, num_addr--) {
crc = crc32_data (&ptr_addr->b[0], 6) >> 26;
if (crc & 0x20) {
dev->regs->MAC_HASH_TAB_1 |= (1 << (crc & 0x1F));
} else {
dev->regs->MAC_HASH_TAB_0 |= (1 << crc);
}
}
/* Enable perfect and hash address filtering */
dev->regs->MAC_PACKET_FILTER |= (MAC_PACKET_FILTER_HPF | MAC_PACKET_FILTER_HMC);
return ARM_DRIVER_OK;
}
/**
\fn int32_t SendFrame (const uint8_t *frame, uint32_t len, uint32_t flags,
MAC_DEV *dev)
\brief Send Ethernet frame.
\param[in] frame Pointer to frame buffer with data to send
\param[in] len Frame buffer length in bytes
\param[in] flags Frame transmit flags (see ARM_ETH_MAC_TX_FRAME_...)
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t SendFrame(const uint8_t *frame, uint32_t len, uint32_t flags,
MAC_DEV *dev)
{
uint32_t cur_idx;
uint8_t *dst;
uint32_t buffer_len = len;
DMA_DESC *desc;
if (!frame || !len)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
cur_idx = dev->tx_desc_id;
desc = &dev->tx_descs[cur_idx];
SCB_InvalidateDCache_by_Addr(desc, sizeof(DMA_DESC));
dst = dev->frame_end;
if (dst == NULL) {
/* new frame */
if (desc->des3 & TDES3_OWN) {
return ARM_DRIVER_ERROR_BUSY;
}
dst = (uint8_t *) &tx_buffers[cur_idx][0];
desc->des2 = TDES2_INTERRUPT_ON_COMPLETION | buffer_len;
} else {
/* frame fragment */
desc->des2 += len;
}
/* Copy the frame to the buffer */
for ( ; len > 7; dst += 8, frame += 8, len -= 8) {
((uint32_t *) dst)[0] = ((uint32_t *) frame)[0];
((uint32_t *) dst)[1] = ((uint32_t *) frame)[1];
}
/* Copy remaining 7 bytes */
for ( ; len > 1; dst += 2, frame += 2, len -= 2)
((uint16_t *) dst)[0] = ((uint16_t *) frame)[0];
if (len > 0)
dst++[0] = frame++[0];
SCB_CleanDCache_by_Addr((uint32_t *) &tx_buffers[cur_idx][0], ETH_BUF_SIZE);
if (flags & ARM_ETH_MAC_TX_FRAME_FRAGMENT) {
/* More data to come, remember current write position */
dev->frame_end = dst;
return ARM_DRIVER_OK;
}
dev->tx_desc_id++;
dev->tx_desc_id %= TX_DESC_COUNT;
desc->des0 = (uint32_t)LocalToGlobal(&tx_buffers[cur_idx][0]);
dev->frame_end = NULL;
desc->des3 = TDES3_OWN | TDES3_LAST_DESCRIPTOR | TDES3_FIRST_DESCRIPTOR |
buffer_len;
SCB_CleanDCache_by_Addr((uint32_t *) desc, sizeof(DMA_DESC));
dev->regs->DMA_CH0_TX_END_ADDR = (uint32_t) LocalToGlobal(&(dev->tx_descs[dev->tx_desc_id]));
return ARM_DRIVER_OK;
}
/**
\fn int32_t ReadFrame (uint8_t *frame, uint32_t len, MAC_DEV *dev)
\brief Read data of received Ethernet frame.
\param[in] frame Pointer to frame buffer for data to read into
\param[in] len Frame buffer length in bytes
\param[in] dev Pointer to the MAC device instance
\return number of data bytes read or execution status
- value >= 0: number of data bytes read
- value < 0: error occurred, value is execution status as defined with \ref execution_status
*/
static int32_t ReadFrame(uint8_t *frame, uint32_t len, MAC_DEV *dev)
{
uint32_t cur_idx;
int32_t buffer_len = (int32_t) len;
uint8_t *src;
if (!frame || !len)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
cur_idx = dev->rx_desc_id;
src = (uint8_t *) &rx_buffers[cur_idx][0];
SCB_InvalidateDCache_by_Addr(src, ETH_BUF_SIZE);
/* copy data to the buffer */
for ( ; len > 7; frame += 8, src += 8, len -= 8) {
((uint32_t *) frame)[0] = ((uint32_t *) src)[0];
((uint32_t *) frame)[1] = ((uint32_t *) src)[1];
}
/* copy remaining 7 bytes */
for ( ; len > 1; frame += 2, src += 2, len -= 2)
((uint16_t *) frame)[0] = ((uint16_t *)src)[0];
if (len > 0)
frame[0] = src[0];
/* refresh the descriptor */
setup_rxdesc(dev, cur_idx);
dev->regs->DMA_CH0_RX_END_ADDR = (uint32_t) LocalToGlobal(&(dev->rx_descs[cur_idx]));
dev->rx_desc_id++;
dev->rx_desc_id %= RX_DESC_COUNT;
return buffer_len;
}
/**
\fn uint32_t GetRxFrameSize (MAC_DEV *dev)
\param[in] dev Pointer to the MAC device instance
\brief Get size of received Ethernet frame.
\return number of bytes in received frame
*/
static uint32_t GetRxFrameSize(MAC_DEV *dev)
{
DMA_DESC *desc;
if (!(dev->flags & ETH_POWER))
return 0;
desc = &dev->rx_descs[dev->rx_desc_id];
SCB_InvalidateDCache_by_Addr(desc, sizeof(DMA_DESC));
if (desc->des3 & RDES3_OWN)
return 0;
return (desc->des3 & 0x7fff) - 4;
}
/**
\fn int32_t GetRxFrameTime (ARM_ETH_MAC_TIME *time, MAC_DEV *dev)
\brief Get time of received Ethernet frame.
\param[in] time Pointer to time structure for data to read into
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t GetRxFrameTime(ARM_ETH_MAC_TIME *time, MAC_DEV *dev)
{
DMA_DESC *desc, *next_desc;
uint32_t cur_idx = dev->rx_desc_id, next_idx;
uint32_t own, ctxt;
if (!time)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
desc = &dev->rx_descs[cur_idx];
next_idx = (cur_idx + 1) % RX_DESC_COUNT;
next_desc = &dev->rx_descs[next_idx];
SCB_InvalidateDCache_by_Addr(desc, sizeof(DMA_DESC));
if (desc->des3 & RDES3_OWN)
return ARM_DRIVER_ERROR_BUSY;
/* get preliminary status from current normal w/b descriptor */
if (!(desc->des3 & RDES3_RDES1_VALID))
return ARM_DRIVER_ERROR;
if (!(desc->des1 & RDES1_TIMESTAMP_AVAILABLE))
return ARM_DRIVER_ERROR;
/* OK, move on to the context descriptor */
own = next_desc->des3 & RDES3_OWN;
ctxt = ((next_desc->des3 & RDES3_CONTEXT_DESCRIPTOR)
>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
if (!own && ctxt) {
if ((next_desc->des0 == 0xffffffff) && (next_desc->des1 == 0xffffffff)) {
/* Corrupted timestamp */
return ARM_DRIVER_ERROR;
}
time->ns = next_desc->des0;
time->sec = next_desc->des1;
return ARM_DRIVER_OK;
}
return ARM_DRIVER_ERROR;
}
/**
\fn int32_t GetTxFrameTime (ARM_ETH_MAC_TIME *time, MAC_DEV *dev)
\brief Get time of transmitted Ethernet frame.
\param[in] time Pointer to time structure for data to read into
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t GetTxFrameTime(ARM_ETH_MAC_TIME *time, MAC_DEV *dev)
{
DMA_DESC *desc;
if (!time)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
desc = &dev->tx_descs[dev->tx_desc_id];
SCB_InvalidateDCache_by_Addr(desc, sizeof(DMA_DESC));
if (desc->des3 & TDES3_OWN)
return ARM_DRIVER_ERROR_BUSY;
if (desc->des3 & TDES3_CONTEXT_TYPE)
return ARM_DRIVER_ERROR;
if (desc->des3 & TDES3_TIMESTAMP_STATUS) {
time->ns = desc->des0;
time->sec = desc->des1;
return ARM_DRIVER_OK;
}
return ARM_DRIVER_ERROR;
}
/**
\fn int32_t Control (uint32_t control, uint32_t arg, MAC_DEV *dev)
\brief Control Ethernet Interface.
\param[in] control Operation
\param[in] arg Argument of operation (optional)
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t Control(uint32_t control, uint32_t arg, MAC_DEV *dev)
{
uint32_t val, reg;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
switch (control) {
case ARM_ETH_MAC_CONFIGURE:
val = dev->regs->MAC_CONFIG &
~(MAC_CONFIG_FES |
MAC_CONFIG_LM |
MAC_CONFIG_DM);
switch (arg & ARM_ETH_MAC_SPEED_Msk) {
case ARM_ETH_MAC_SPEED_10M:
/* Nothing to do here as FES is already cleared */
break;
case ARM_ETH_SPEED_100M:
val |= MAC_CONFIG_FES;
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
switch (arg & ARM_ETH_MAC_DUPLEX_Msk) {
case ARM_ETH_MAC_DUPLEX_FULL:
val |= MAC_CONFIG_DM;
break;
}
if (arg & ARM_ETH_MAC_LOOPBACK)
val |= MAC_CONFIG_LM;
if ((arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_RX) ||
(arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_TX))
return ARM_DRIVER_ERROR_UNSUPPORTED;
dev->regs->MAC_CONFIG = val;
val = (dev->regs->MAC_PACKET_FILTER) & ~(MAC_PACKET_FILTER_PR |
MAC_PACKET_FILTER_PM |
MAC_PACKET_FILTER_DBF);
/* Disable broadcast frame reception */
if (!(arg & ARM_ETH_MAC_ADDRESS_BROADCAST))
val |= MAC_PACKET_FILTER_DBF;
/* Enable multicast frame reception */
if (arg & ARM_ETH_MAC_ADDRESS_MULTICAST)
val |= MAC_PACKET_FILTER_PM;
/* Promiscuous mode */
if (arg & ARM_ETH_MAC_ADDRESS_ALL)
val |= MAC_PACKET_FILTER_PR;
dev->regs->MAC_PACKET_FILTER = val;
break;
case ARM_ETH_MAC_CONTROL_TX:
val = dev->regs->MAC_CONFIG;
reg = dev->regs->DMA_CH0_TX_CTRL;
if (arg != 0) {
val |= MAC_CONFIG_TE;
reg |= DMA_CONTROL_ST;
dev->regs->MAC_CONFIG = val;
dev->regs->DMA_CH0_TX_CTRL = reg;
} else {
reg &= ~DMA_CONTROL_ST;
val &= ~MAC_CONFIG_TE;
dev->regs->DMA_CH0_TX_CTRL = reg;
dev->regs->MAC_CONFIG = val;
}
break;
case ARM_ETH_MAC_CONTROL_RX:
val = dev->regs->MAC_CONFIG;
reg = dev->regs->DMA_CH0_RX_CTRL;
if (arg != 0) {
val |= MAC_CONFIG_RE;
reg |= DMA_CONTROL_SR;
dev->regs->MAC_CONFIG = val;
dev->regs->DMA_CH0_RX_CTRL = reg;
} else {
reg &= ~DMA_CONTROL_SR;
val &= ~MAC_CONFIG_RE;
dev->regs->DMA_CH0_RX_CTRL = reg;
dev->regs->MAC_CONFIG = val;
}
break;
case ARM_ETH_MAC_FLUSH:
if (arg & ARM_ETH_MAC_FLUSH_RX) {
val = dev->regs->DMA_CH0_RX_CTRL;
reg = val;
val &= ~DMA_CONTROL_SR;
dev->regs->DMA_CH0_RX_CTRL = val;
init_rx_descs(dev);
dev->regs->DMA_CH0_RX_CTRL = reg;
}
if (arg & ARM_ETH_MAC_FLUSH_TX) {
val = dev->regs->DMA_CH0_TX_CTRL;
reg = val;
val &= ~DMA_CONTROL_ST;
dev->regs->DMA_CH0_TX_CTRL = val;
init_tx_descs(dev);
dev->regs->DMA_CH0_TX_CTRL = reg;
}
break;
case ARM_ETH_MAC_SLEEP:
if (arg != 0) {
dev->regs->DMA_CH0_TX_CTRL &= ~DMA_CONTROL_ST;
dev->regs->MAC_CONFIG &= ~(MAC_CONFIG_TE | MAC_CONFIG_RE);
dev->regs->MAC_INT_ENABLE |= MAC_INT_EN_PMTIE;
dev->regs->MAC_CONFIG |= MAC_CONFIG_RE;
dev->regs->MAC_PMT_CTRL_STS |= (MAC_PMT_CTRL_STS_MGKPKTEN | MAC_PMT_CTRL_STS_PWRDWN);
} else {
dev->regs->MAC_INT_ENABLE &= ~MAC_INT_EN_PMTIE;
dev->regs->MAC_PMT_CTRL_STS = 0x0;
}
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t ControlTimer (uint32_t control, ARM_ETH_MAC_TIME *time, MAC_DEV *dev)
\brief Control Precision Timer.
\param[in] control Operation
\param[in] time Pointer to time structure
\param[in] dev Pointer to the MAC device instance
\return \ref ARM_DRIVER_ERROR_UNSUPPORTED
*/
static int32_t ControlTimer(uint32_t control, ARM_ETH_MAC_TIME *time, MAC_DEV *dev)
{
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
/**
\fn int32_t PHY_Read (uint8_t phy_addr, uint8_t reg_addr, uint16_t *data, MAC_DEV *dev)
\brief Read Ethernet PHY Register through Management Interface.
\param[in] phy_addr 5-bit device address
\param[in] reg_addr 5-bit register address
\param[out] data Pointer where the result is written to
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t PHY_Read(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data,
MAC_DEV *dev)
{
uint32_t val, timeout = 5;
if (!data)
return ARM_DRIVER_ERROR_PARAMETER;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
val = (phy_addr << MAC_MDIO_ADDR_PA_SHIFT) |
(reg_addr << MAC_MDIO_ADDR_RDA_SHIFT) |
(MAC_MDIO_ADDR_GOC_READ << MAC_MDIO_ADDR_GOC_SHIFT) |
(MAC_MDIO_ADDR_CR_150_250 << MAC_MDIO_ADDR_CR_SHIFT)|
MAC_MDIO_ADDR_GB;
dev->regs->MAC_MDIO_ADDR = val;
do {
if (!(dev->regs->MAC_MDIO_ADDR & MAC_MDIO_ADDR_GB)) {
*data = dev->regs->MAC_MDIO_DATA;
break;
}
osDelay(1);
timeout--;
} while(timeout);
if (!timeout)
return ARM_DRIVER_ERROR_TIMEOUT;
return ARM_DRIVER_OK;
}
/**
\fn int32_t PHY_Write (uint8_t phy_addr, uint8_t reg_addr, uint16_t data,
MAC_DEV *dev)
\brief Write Ethernet PHY Register through Management Interface.
\param[in] phy_addr 5-bit device address
\param[in] reg_addr 5-bit register address
\param[in] data 16-bit data to write
\param[in] dev Pointer to the MAC device instance
\return \ref execution_status
*/
static int32_t PHY_Write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data,
MAC_DEV *dev)
{
uint32_t val, timeout = 5;
if (!(dev->flags & ETH_POWER))
return ARM_DRIVER_ERROR;
val = (phy_addr << MAC_MDIO_ADDR_PA_SHIFT) |
(reg_addr << MAC_MDIO_ADDR_RDA_SHIFT) |
(MAC_MDIO_ADDR_GOC_WRITE << MAC_MDIO_ADDR_GOC_SHIFT) |
(MAC_MDIO_ADDR_CR_150_250 << MAC_MDIO_ADDR_CR_SHIFT) |
MAC_MDIO_ADDR_GB;
dev->regs->MAC_MDIO_DATA = data;
dev->regs->MAC_MDIO_ADDR = val;
do {
if (!(dev->regs->MAC_MDIO_ADDR & MAC_MDIO_ADDR_GB))
break;
osDelay(1);
timeout--;
} while(timeout);
if (!timeout)
return ARM_DRIVER_ERROR_TIMEOUT;
return ARM_DRIVER_OK;
}
/**
\fn void ETH_IRQHandler (MAC_DEV *dev)
\param[in] dev Pointer to the MAC device instance
\brief MAC instance specific part of Ethernet Interrupt handler.
*/
static void ETH_IRQHandler(MAC_DEV *dev)
{
uint32_t ch0_stat, event = 0;
if (dev->regs->DMA_STATUS & DMA_STATUS_CHAN0) {
ch0_stat = dev->regs->DMA_CH0_STATUS;
dev->regs->DMA_CH0_STATUS =
ch0_stat & (DMA_CHAN_STATUS_NIS | DMA_CHAN_STATUS_RI | DMA_CHAN_STATUS_TI);
if (ch0_stat & DMA_CHAN_STATUS_RI)
event |= ARM_ETH_MAC_EVENT_RX_FRAME;
if (ch0_stat & DMA_CHAN_STATUS_TI)
event |= ARM_ETH_MAC_EVENT_TX_FRAME;
if (event && dev->cb_event)
dev->cb_event(event);
}
}
/**
\fn void ETH_SBD_IRQHandler (void)
\brief Ethernet Interrupt handler.
*/
void ETH_SBD_IRQHandler(void)
{
ETH_IRQHandler(&MAC0);
}
/**
\fn int32_t ETH_MAC0_Initialize (ARM_ETH_MAC_SignalEvent_t cb_event)
\brief Initialize Ethernet MAC Device.
\param[in] cb_event Pointer to \ref ARM_ETH_MAC_SignalEvent
\return \ref execution_status
*/
static int32_t ETH_MAC0_Initialize(ARM_ETH_MAC_SignalEvent_t cb_event)
{
return Initialize(cb_event, &MAC0);
}
/**
\fn int32_t ETH_MAC0_Uninitialize (void)
\brief De-initialize Ethernet MAC Device.
\return \ref execution_status
*/
static int32_t ETH_MAC0_Uninitialize(void)
{
return Uninitialize(&MAC0);
}
/**
\fn int32_t ETH_MAC0_PowerControl (ARM_POWER_STATE state)
\brief Control Ethernet MAC Device Power.
\param[in] state Power state
\return \ref execution_status
*/
static int32_t ETH_MAC0_PowerControl(ARM_POWER_STATE state)
{
return PowerControl(state, &MAC0);
}
/**
\fn int32_t ETH_MAC0_GetMacAddress (ARM_ETH_MAC_ADDR *ptr_addr)
\brief Get Ethernet MAC Address.
\param[in] ptr_addr Pointer to address
\return \ref execution_status
*/
static int32_t ETH_MAC0_GetMacAddress(ARM_ETH_MAC_ADDR *ptr_addr)
{
return GetMacAddress(ptr_addr, &MAC0);
}
/**
\fn int32_t ETH_MAC0_SetMacAddress (const ARM_ETH_MAC_ADDR *ptr_addr)
\brief Set Ethernet MAC Address.
\param[in] ptr_addr Pointer to address
\return \ref execution_status
*/
static int32_t ETH_MAC0_SetMacAddress(const ARM_ETH_MAC_ADDR *ptr_addr)
{
return SetMacAddress(ptr_addr, &MAC0);
}
/**
\fn int32_t ETH_MAC0_SetAddressFilter (const ARM_ETH_MAC_ADDR *ptr_addr,
uint32_t num_addr)
\brief Configure Address Filter.
\param[in] ptr_addr Pointer to addresses
\param[in] num_addr Number of addresses to configure
\return \ref execution_status
*/
static int32_t ETH_MAC0_SetAddressFilter(const ARM_ETH_MAC_ADDR *ptr_addr, uint32_t num_addr)
{
return SetAddressFilter(ptr_addr, num_addr, &MAC0);
}
/**
\fn int32_t ETH_MAC0_SendFrame (const uint8_t *frame, uint32_t len, uint32_t flags)
\brief Send Ethernet frame.
\param[in] frame Pointer to frame buffer with data to send
\param[in] len Frame buffer length in bytes
\param[in] flags Frame transmit flags (see ARM_ETH_MAC_TX_FRAME_...)
\return \ref execution_status
*/
static int32_t ETH_MAC0_SendFrame(const uint8_t *frame, uint32_t len, uint32_t flags)
{
return SendFrame(frame, len, flags, &MAC0);
}
/**
\fn int32_t ETH_MAC0_ReadFrame (uint8_t *frame, uint32_t len)
\brief Read data of received Ethernet frame.
\param[in] frame Pointer to frame buffer for data to read into
\param[in] len Frame buffer length in bytes
\return number of data bytes read or execution status
- value >= 0: number of data bytes read
- value < 0: error occurred, value is execution status as defined with \ref execution_status
*/
static int32_t ETH_MAC0_ReadFrame(uint8_t *frame, uint32_t len)
{
return ReadFrame(frame, len, &MAC0);
}
/**
\fn uint32_t ETH_MAC0_GetRxFrameSize (void)
\brief Get size of received Ethernet frame.
\return number of bytes in received frame
*/
static uint32_t ETH_MAC0_GetRxFrameSize(void)
{
return GetRxFrameSize(&MAC0);
}
/**
\fn int32_t ETH_MAC0_GetRxFrameTime (ARM_ETH_MAC_TIME *time)
\brief Get time of received Ethernet frame.
\param[in] time Pointer to time structure for data to read into
\return \ref execution_status
*/
static int32_t ETH_MAC0_GetRxFrameTime(ARM_ETH_MAC_TIME *time)
{
return GetRxFrameTime(time, &MAC0);
}
/**
\fn int32_t ETH_MAC0_Control (uint32_t control, uint32_t arg)
\brief Control Ethernet Interface.
\param[in] control Operation
\param[in] arg Argument of operation (optional)
\return \ref execution_status
*/
static int32_t ETH_MAC0_GetTxFrameTime(ARM_ETH_MAC_TIME *time)
{
return GetTxFrameTime(time, &MAC0);
}
/**
\fn int32_t ETH_MAC0_Control (uint32_t control, uint32_t arg)
\brief Control Ethernet Interface.
\param[in] control Operation
\param[in] arg Argument of operation (optional)
\return \ref execution_status
*/
static int32_t ETH_MAC0_Control(uint32_t control, uint32_t arg)
{
return Control(control, arg, &MAC0);
}
/**
\fn int32_t ETH_MAC0_ControlTimer (uint32_t control, ARM_ETH_MAC_TIME *time)
\brief Control Precision Timer.
\param[in] control Operation
\param[in] time Pointer to time structure
\return \ref execution_status
*/
static int32_t ETH_MAC0_ControlTimer(uint32_t control, ARM_ETH_MAC_TIME *time)
{
return ControlTimer(control, time, &MAC0);
}
/**
\fn int32_t ETH_MAC0_PHY_Read (uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
\brief Read Ethernet PHY Register through Management Interface.
\param[in] phy_addr 5-bit device address
\param[in] reg_addr 5-bit register address
\param[out] data Pointer where the result is written to
\return \ref execution_status
*/
static int32_t ETH_MAC0_PHY_Read(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
{
return PHY_Read(phy_addr, reg_addr, data, &MAC0);
}
/**
\fn int32_t ETH_MAC0_PHY_Write (uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
\brief Write Ethernet PHY Register through Management Interface.
\param[in] phy_addr 5-bit device address
\param[in] reg_addr 5-bit register address
\param[in] data 16-bit data to write
\return \ref execution_status
*/
static int32_t ETH_MAC0_PHY_Write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
{
return PHY_Write(phy_addr, reg_addr, data, &MAC0);
}
ARM_DRIVER_ETH_MAC Driver_ETH_MAC0 =
{
ETH_MAC_GetVersion,
ETH_MAC_GetCapabilities,
ETH_MAC0_Initialize,
ETH_MAC0_Uninitialize,
ETH_MAC0_PowerControl,
ETH_MAC0_GetMacAddress,
ETH_MAC0_SetMacAddress,
ETH_MAC0_SetAddressFilter,
ETH_MAC0_SendFrame,
ETH_MAC0_ReadFrame,
ETH_MAC0_GetRxFrameSize,
ETH_MAC0_GetRxFrameTime,
ETH_MAC0_GetTxFrameTime,
ETH_MAC0_ControlTimer,
ETH_MAC0_Control,
ETH_MAC0_PHY_Read,
ETH_MAC0_PHY_Write
};