GMAC driver
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@11166 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
0684b80fe1
commit
58883bb41b
|
@ -0,0 +1,9 @@
|
||||||
|
ifeq ($(USE_SMART_BUILD),yes)
|
||||||
|
ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),)
|
||||||
|
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1
|
|
@ -0,0 +1,826 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file MACv1/hal_mac_lld.c
|
||||||
|
* @brief SAMA low level MAC driver code.
|
||||||
|
*
|
||||||
|
* @addtogroup MAC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||||
|
|
||||||
|
#include "hal_mii.h"
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local definitions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
#define BUFFER_SIZE ((((SAMA_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4)
|
||||||
|
|
||||||
|
/* MII divider optimal value.*/
|
||||||
|
#if (SAMA_GMAC0CLK <= 20000000)
|
||||||
|
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_8
|
||||||
|
#elif (SAMA_GMAC0CLK <= 40000000)
|
||||||
|
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_16
|
||||||
|
#elif (SAMA_GMAC0CLK <= 80000000)
|
||||||
|
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_32
|
||||||
|
#elif (SAMA_GMAC0CLK <= 120000000)
|
||||||
|
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_48
|
||||||
|
#elif (SAMA_GMAC0CLK <= 160000000)
|
||||||
|
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_64
|
||||||
|
#elif (SAMA_GMAC0CLK <= 240000000)
|
||||||
|
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_96
|
||||||
|
#else
|
||||||
|
#error "MCK too high, cannot configure MDC clock"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @brief Ethernet driver 0.
|
||||||
|
*/
|
||||||
|
MACDriver ETHD0;
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local variables and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
static const uint8_t default_mac_address[] = {0x54, 0x54, 0x08, 0x34, 0x1f, 0x3a};
|
||||||
|
|
||||||
|
/* Rx descriptor list */
|
||||||
|
ALIGNED_VAR(8)
|
||||||
|
static sama_eth_rx_descriptor_t __eth_rd[SAMA_MAC_RECEIVE_BUFFERS];
|
||||||
|
|
||||||
|
/* Tx descriptor list */
|
||||||
|
ALIGNED_VAR(8)
|
||||||
|
static sama_eth_tx_descriptor_t __eth_td[SAMA_MAC_TRANSMIT_BUFFERS];
|
||||||
|
|
||||||
|
static uint32_t __eth_rb[SAMA_MAC_RECEIVE_BUFFERS][BUFFER_SIZE];
|
||||||
|
static uint32_t __eth_tb[SAMA_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE];
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @brief Configures ETH pins.
|
||||||
|
* TODO: move into board.c
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void configurePinsETH(void) {
|
||||||
|
palSetGroupMode(PIOB, PAL_PORT_BIT(PIOB_ETH_GTXCK) | PAL_PORT_BIT(PIOB_ETH_GTXEN) |
|
||||||
|
PAL_PORT_BIT(PIOB_ETH_GRXDV) | PAL_PORT_BIT(PIOB_ETH_GRXER) |
|
||||||
|
PAL_PORT_BIT(PIOB_ETH_GRX0) | PAL_PORT_BIT(PIOB_ETH_GRX1) |
|
||||||
|
PAL_PORT_BIT(PIOB_ETH_GTX0) | PAL_PORT_BIT(PIOB_ETH_GTX1) |
|
||||||
|
PAL_PORT_BIT(PIOB_ETH_GMDC) | PAL_PORT_BIT(PIOB_ETH_GMDIO),
|
||||||
|
0U, PAL_SAMA_FUNC_PERIPH_F | PAL_MODE_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits for phy management logic idle.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
#define phyWaitIdle() { \
|
||||||
|
while ((GMAC0->GMAC_NSR & GMAC_NSR_IDLE) == 0) { \
|
||||||
|
; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @brief Writes a PHY register.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
* @param[in] reg_addr register address
|
||||||
|
* @param[in] value new register value
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void mii_write(MACDriver *macp, uint32_t reg_addr, uint32_t value) {
|
||||||
|
|
||||||
|
phyWaitIdle();
|
||||||
|
|
||||||
|
/* Write maintenance register (Clause 22) */
|
||||||
|
GMAC0->GMAC_MAN = GMAC_MAN_CLTTO | GMAC_MAN_OP(1) | GMAC_MAN_WTN(2) |
|
||||||
|
GMAC_MAN_PHYA(macp->phyaddr) | GMAC_MAN_REGA(reg_addr) |
|
||||||
|
GMAC_MAN_DATA(value);
|
||||||
|
phyWaitIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a PHY register.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
* @param[in] reg_addr register address
|
||||||
|
*
|
||||||
|
* @return The PHY register content.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
uint32_t mii_read(MACDriver *macp, uint32_t reg_addr) {
|
||||||
|
|
||||||
|
phyWaitIdle();
|
||||||
|
|
||||||
|
/* Read maintenance register */
|
||||||
|
GMAC0->GMAC_MAN = GMAC_MAN_CLTTO | GMAC_MAN_OP(2) | GMAC_MAN_WTN(2) |
|
||||||
|
GMAC_MAN_PHYA(macp->phyaddr) | GMAC_MAN_REGA(reg_addr);
|
||||||
|
phyWaitIdle();
|
||||||
|
|
||||||
|
return (uint32_t) ((GMAC0->GMAC_MAN) & GMAC_MAN_DATA_Msk >> GMAC_MAN_DATA_Pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(BOARD_PHY_ADDRESS)
|
||||||
|
/**
|
||||||
|
* @brief PHY address detection.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
*/
|
||||||
|
static void mii_find_phy(MACDriver *macp) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
#if SAMA_MAC_PHY_TIMEOUT > 0
|
||||||
|
unsigned n = SAMA_MAC_PHY_TIMEOUT;
|
||||||
|
do {
|
||||||
|
#endif
|
||||||
|
for (i = 1U; i < 31U; i++) {
|
||||||
|
macp->phyaddr = i;
|
||||||
|
if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) &&
|
||||||
|
((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if SAMA_MAC_PHY_TIMEOUT > 0
|
||||||
|
n--;
|
||||||
|
} while (n > 0U);
|
||||||
|
#endif
|
||||||
|
/* Wrong or defective board.*/
|
||||||
|
osalSysHalt("MAC failure");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MAC address setup.
|
||||||
|
*
|
||||||
|
* @param[in] p pointer to a six bytes buffer containing the MAC
|
||||||
|
* address
|
||||||
|
*/
|
||||||
|
static void mac_lld_set_address(const uint8_t *p) {
|
||||||
|
|
||||||
|
/* MAC address configuration, only a single address comparator is used,
|
||||||
|
hash table not used.*/
|
||||||
|
GMAC0->GMAC_SA[0].GMAC_SAB = (p[3] << 24) | (p[2] << 16) |
|
||||||
|
(p[1] << 8) | p[0];
|
||||||
|
GMAC0->GMAC_SA[0].GMAC_SAT = (p[5] << 8) | p[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver interrupt handlers. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
OSAL_IRQ_HANDLER(SAMA_ETH_HANDLER) {
|
||||||
|
uint32_t isr;
|
||||||
|
uint32_t rsr;
|
||||||
|
uint32_t tsr;
|
||||||
|
|
||||||
|
OSAL_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
isr = GMAC0->GMAC_ISR;
|
||||||
|
rsr = GMAC0->GMAC_RSR;
|
||||||
|
tsr = GMAC0->GMAC_TSR;
|
||||||
|
|
||||||
|
if (isr & GMAC_ISR_RCOMP) {
|
||||||
|
/* Data Received.*/
|
||||||
|
osalSysLockFromISR();
|
||||||
|
/* Clear Status Register */
|
||||||
|
GMAC0->GMAC_RSR = rsr;
|
||||||
|
osalThreadDequeueAllI(ÐD0.rdqueue, MSG_RESET);
|
||||||
|
#if MAC_USE_EVENTS
|
||||||
|
osalEventBroadcastFlagsI(ÐD0.rdevent, 0);
|
||||||
|
#endif
|
||||||
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isr & GMAC_ISR_TCOMP) {
|
||||||
|
/* Data Transmitted.*/
|
||||||
|
osalSysLockFromISR();
|
||||||
|
/* Clear Status Register */
|
||||||
|
GMAC0->GMAC_TSR = tsr;
|
||||||
|
osalThreadDequeueAllI(ÐD0.tdqueue, MSG_RESET);
|
||||||
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
aicAckInt();
|
||||||
|
OSAL_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level MAC initialization.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void mac_lld_init(void) {
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
configurePinsETH();
|
||||||
|
macObjectInit(ÐD0);
|
||||||
|
ETHD0.link_up = false;
|
||||||
|
|
||||||
|
/* Descriptor tables are initialized in chained mode, note that the status
|
||||||
|
word is not initialized here but in mac_lld_start().*/
|
||||||
|
for (i = 0; i < SAMA_MAC_RECEIVE_BUFFERS; i++) {
|
||||||
|
__eth_rd[i].rdes0 = ((uint32_t)__eth_rb[i]) & (SAMA_RDES0_RBAP_MASK);
|
||||||
|
/* Status reset */
|
||||||
|
__eth_rd[i].rdes1 = 0;
|
||||||
|
/* For last buffer wrap is set */
|
||||||
|
if (i == (SAMA_MAC_RECEIVE_BUFFERS - 1)){
|
||||||
|
__eth_rd[i].rdes0 |= SAMA_RDES0_WRAP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < SAMA_MAC_TRANSMIT_BUFFERS; i++) {
|
||||||
|
__eth_td[i].tdes0 = (uint32_t)__eth_tb[i];
|
||||||
|
/* Status reset */
|
||||||
|
__eth_td[i].tdes1 = 0;
|
||||||
|
/* For last buffer wrap is set */
|
||||||
|
if (i == (SAMA_MAC_TRANSMIT_BUFFERS - 1)){
|
||||||
|
__eth_td[i].tdes1 |= SAMA_TDES1_WRAP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configures MDIO clock */
|
||||||
|
GMAC0->GMAC_NCFGR = (GMAC0->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | GMAC_CLK;
|
||||||
|
|
||||||
|
/* Enables management port */
|
||||||
|
GMAC0->GMAC_NCR |= GMAC_NCR_MPE;
|
||||||
|
|
||||||
|
/* Selection of the RMII or MII mode based on info exported by board.h.*/
|
||||||
|
#if defined(BOARD_PHY_RMII)
|
||||||
|
GMAC0->GMAC_UR = GMAC_UR_RMII;
|
||||||
|
#else
|
||||||
|
GMAC0->GMAC_UR &= ~GMAC_UR_RMII;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MAC clocks temporary activation.*/
|
||||||
|
pmcEnableETH0();
|
||||||
|
/* PHY address setup.*/
|
||||||
|
#if defined(BOARD_PHY_ADDRESS)
|
||||||
|
ETHD0.phyaddr = BOARD_PHY_ADDRESS;
|
||||||
|
#else
|
||||||
|
mii_find_phy(ÐD0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOARD_PHY_RESET)
|
||||||
|
/* PHY board-specific reset procedure.*/
|
||||||
|
BOARD_PHY_RESET();
|
||||||
|
#else
|
||||||
|
/* PHY soft reset procedure.*/
|
||||||
|
mii_write(ÐD0, MII_BMCR, BMCR_RESET);
|
||||||
|
#if defined(BOARD_PHY_RESET_DELAY)
|
||||||
|
osalSysPolledDelayX(BOARD_PHY_RESET_DELAY);
|
||||||
|
#endif
|
||||||
|
while (mii_read(ÐD0, MII_BMCR) & BMCR_RESET)
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SAMA_MAC_ETH0_CHANGE_PHY_STATE
|
||||||
|
/* PHY in power down mode until the driver will be started.*/
|
||||||
|
mii_write(ÐD0, MII_BMCR, mii_read(ÐD0, MII_BMCR) | BMCR_PDOWN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MAC clocks stopped again. */
|
||||||
|
pmcDisableETH0();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures and activates the MAC peripheral.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void mac_lld_start(MACDriver *macp) {
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
GMAC0->GMAC_IDR = 0xFFFFFFFF; /* Queue 0 */
|
||||||
|
GMAC0->GMAC_IDRPQ[0] = 0xFFFFFFFF; /* Queue 1 */
|
||||||
|
GMAC0->GMAC_IDRPQ[1] = 0xFFFFFFFF; /* Queue 2 */
|
||||||
|
|
||||||
|
/* Clear statistic */
|
||||||
|
GMAC0->GMAC_NCR |= GMAC_NCR_CLRSTAT;
|
||||||
|
|
||||||
|
/* Clear rx and tx status bit */
|
||||||
|
GMAC0->GMAC_RSR = 0xF;
|
||||||
|
GMAC0->GMAC_TSR = 0xFF;
|
||||||
|
|
||||||
|
/* Clear interrupt status register */
|
||||||
|
GMAC0->GMAC_ISR; /* Queue 0 */
|
||||||
|
GMAC0->GMAC_ISRPQ[0]; /* Queue 1 */
|
||||||
|
GMAC0->GMAC_ISRPQ[1]; /* Queue 2 */
|
||||||
|
|
||||||
|
/* Free all descriptors.*/
|
||||||
|
for (i = 0; i < SAMA_MAC_RECEIVE_BUFFERS; i++)
|
||||||
|
__eth_rd[i].rdes0 &= ~SAMA_RDES0_OWN;
|
||||||
|
|
||||||
|
/* Current receive descriptor */
|
||||||
|
macp->rxptr = (sama_eth_rx_descriptor_t *)__eth_rd;
|
||||||
|
|
||||||
|
for (i = 0; i < SAMA_MAC_TRANSMIT_BUFFERS; i++)
|
||||||
|
__eth_td[i].tdes1 |= SAMA_TDES1_LAST_BUFF | SAMA_TDES1_USED;
|
||||||
|
|
||||||
|
macp->txptr = (sama_eth_tx_descriptor_t *)__eth_td;
|
||||||
|
|
||||||
|
/* MAC clocks activation and commanded reset procedure.*/
|
||||||
|
pmcEnableETH0();
|
||||||
|
|
||||||
|
/* Enable interrupt */
|
||||||
|
aicSetSourcePriority(ID_GMAC0, SAMA_MAC_ETH0_IRQ_PRIORITY);
|
||||||
|
aicSetSourceHandler(ID_GMAC0, SAMA_ETH_HANDLER);
|
||||||
|
aicEnableInt(ID_GMAC0);
|
||||||
|
|
||||||
|
#if SAMA_MAC_ETH0_CHANGE_PHY_STATE
|
||||||
|
/* PHY in power up mode.*/
|
||||||
|
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MAC address setup.*/
|
||||||
|
if (macp->config->mac_address == NULL)
|
||||||
|
mac_lld_set_address(default_mac_address);
|
||||||
|
else
|
||||||
|
mac_lld_set_address(macp->config->mac_address);
|
||||||
|
|
||||||
|
/* Transmitter and receiver enabled.
|
||||||
|
Note that the complete setup of the MAC is performed when the link
|
||||||
|
status is detected.*/
|
||||||
|
uint32_t ncfgr = GMAC0->GMAC_NCFGR;
|
||||||
|
|
||||||
|
#if SAMA_MAC_IP_CHECKSUM_OFFLOAD
|
||||||
|
GMAC0->GMAC_NCFGR = GMAC_NCFGR_RXCOEN | GMAC_NCFGR_SPD |
|
||||||
|
GMAC_NCFGR_FD | GMAC_NCFGR_MAXFS |
|
||||||
|
GMAC_NCFGR_RFCS | ncfgr;
|
||||||
|
GMAC0->GMAC_DCFGR |= GMAC_DCFGR_TXCOEN;
|
||||||
|
#else
|
||||||
|
GMAC0->GMAC_NCFGR = GMAC_NCFGR_SPD | GMAC_NCFGR_FD |
|
||||||
|
GMAC_NCFGR_MAXFS | GMAC_NCFGR_RFCS |
|
||||||
|
ncfgr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DMA configuration:
|
||||||
|
* Descriptor chains pointers.
|
||||||
|
*/
|
||||||
|
GMAC0->GMAC_RBQB = (uint32_t)__eth_rd;
|
||||||
|
/*
|
||||||
|
* The queue pointers must be initialized and point to
|
||||||
|
* USED descriptor for all queues including those not
|
||||||
|
* intended for use.
|
||||||
|
*/
|
||||||
|
GMAC0->GMAC_RBQBAPQ[0] = (uint32_t)__eth_rd;
|
||||||
|
GMAC0->GMAC_RBQBAPQ[1] = (uint32_t)__eth_rd;
|
||||||
|
|
||||||
|
GMAC0->GMAC_TBQB = (uint32_t)__eth_td;
|
||||||
|
/*
|
||||||
|
* The queue pointers must be initialized and point to
|
||||||
|
* USED descriptor for alla queues including those not
|
||||||
|
* intended for use.
|
||||||
|
*/
|
||||||
|
GMAC0->GMAC_TBQBAPQ[0] = (uint32_t)__eth_td;
|
||||||
|
GMAC0->GMAC_TBQBAPQ[1] = (uint32_t)__eth_td;
|
||||||
|
|
||||||
|
/* Enabling required interrupt sources.*/
|
||||||
|
GMAC0->GMAC_IER = GMAC_IER_TCOMP | GMAC_IER_RCOMP;
|
||||||
|
|
||||||
|
/* DMA general settings.*/
|
||||||
|
uint32_t dcfgr = GMAC0->GMAC_DCFGR & 0xFFFF;
|
||||||
|
GMAC0->GMAC_DCFGR = dcfgr | GMAC_DCFGR_DRBS(24);
|
||||||
|
|
||||||
|
/* Enable RX and TX.*/
|
||||||
|
GMAC0->GMAC_NCR |= GMAC_NCR_RXEN | GMAC_NCR_TXEN;
|
||||||
|
|
||||||
|
/* Starts transmission */
|
||||||
|
// GMAC0->GMAC_NCR |= GMAC_NCR_TSTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deactivates the MAC peripheral.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void mac_lld_stop(MACDriver *macp) {
|
||||||
|
|
||||||
|
if (macp->state != MAC_STOP) {
|
||||||
|
#if SAMA_MAC_ETH0_CHANGE_PHY_STATE
|
||||||
|
/* PHY in power down mode until the driver will be restarted.*/
|
||||||
|
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Reset Network Control Register */
|
||||||
|
GMAC0->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
GMAC0->GMAC_IDR = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
/* Clear statistic */
|
||||||
|
GMAC0->GMAC_NCR |= GMAC_NCR_CLRSTAT;
|
||||||
|
|
||||||
|
/* Clear rx and tx status bit */
|
||||||
|
GMAC0->GMAC_RSR = 0xF;
|
||||||
|
GMAC0->GMAC_TSR = 0xFF;
|
||||||
|
|
||||||
|
/* Clear interrupt status register */
|
||||||
|
GMAC0->GMAC_ISR;
|
||||||
|
|
||||||
|
/* MAC clocks stopped.*/
|
||||||
|
pmcDisableETH0();
|
||||||
|
|
||||||
|
/* ISR vector disabled.*/
|
||||||
|
aicDisableInt(ID_GMAC0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a transmission descriptor.
|
||||||
|
* @details One of the available transmission descriptors is locked and
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
* @param[out] tdp pointer to a @p MACTransmitDescriptor structure
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval MSG_OK the descriptor has been obtained.
|
||||||
|
* @retval MSG_TIMEOUT descriptor not available.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
|
||||||
|
MACTransmitDescriptor *tdp) {
|
||||||
|
sama_eth_tx_descriptor_t *tdes;
|
||||||
|
|
||||||
|
if (!macp->link_up)
|
||||||
|
return MSG_TIMEOUT;
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
|
||||||
|
/* Get Current TX descriptor.*/
|
||||||
|
tdes = macp->txptr;
|
||||||
|
|
||||||
|
/* Ensure that descriptor isn't owned by the Ethernet DMA or locked by
|
||||||
|
another thread.*/
|
||||||
|
if ((tdes->tdes1 & SAMA_TDES1_LOCKED) | (!(tdes->tdes1 & SAMA_TDES1_USED))) {
|
||||||
|
osalSysUnlock();
|
||||||
|
return MSG_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Marks the current descriptor as locked using a reserved bit.*/
|
||||||
|
tdes->tdes1 |= SAMA_TDES1_LOCKED;
|
||||||
|
|
||||||
|
if (!(tdes->tdes1 & SAMA_TDES1_WRAP)) {
|
||||||
|
macp->txptr += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
macp->txptr = (sama_eth_tx_descriptor_t *)__eth_td;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
/* Set the buffer size and configuration.*/
|
||||||
|
tdp->offset = 0;
|
||||||
|
tdp->size = SAMA_MAC_BUFFERS_SIZE;
|
||||||
|
tdp->physdesc = tdes;
|
||||||
|
|
||||||
|
return MSG_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases a transmit descriptor and starts the transmission of the
|
||||||
|
* enqueued data as a single frame.
|
||||||
|
*
|
||||||
|
* @param[in] tdp the pointer to the @p MACTransmitDescriptor structure
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) {
|
||||||
|
|
||||||
|
osalDbgAssert(tdp->physdesc->tdes1 & SAMA_TDES1_USED,
|
||||||
|
"attempt to release descriptor already owned by DMA");
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
|
||||||
|
/* Unlocks the descriptor and returns it to the DMA engine.*/
|
||||||
|
tdp->physdesc->tdes1 = SAMA_TDES1_LAST_BUFF | (SAMA_TDES1_LENGTH_BUFF & BUFFER_SIZE);
|
||||||
|
|
||||||
|
/* Wait for the write to tdes1 to go through before resuming the DMA.*/
|
||||||
|
__DSB();
|
||||||
|
|
||||||
|
if (!(GMAC0->GMAC_TSR & GMAC_TSR_TXGO)) {
|
||||||
|
GMAC0->GMAC_NCR |= GMAC_NCR_TSTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a receive descriptor.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
* @param[out] rdp pointer to a @p MACReceiveDescriptor structure
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval MSG_OK the descriptor has been obtained.
|
||||||
|
* @retval MSG_TIMEOUT descriptor not available.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
|
||||||
|
MACReceiveDescriptor *rdp) {
|
||||||
|
sama_eth_rx_descriptor_t *rdes;
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
|
||||||
|
/* Get Current RX descriptor.*/
|
||||||
|
rdes = macp->rxptr;
|
||||||
|
|
||||||
|
/* Iterates through received frames until a valid one is found, invalid
|
||||||
|
frames are discarded.*/
|
||||||
|
while (rdes->rdes0 & SAMA_RDES0_OWN) {
|
||||||
|
if (rdes->rdes1 & (SAMA_RDES1_EOF | SAMA_RDES1_SOF)
|
||||||
|
#if SAMA_MAC_IP_CHECKSUM_OFFLOAD
|
||||||
|
&& (rdes->rdes1 & (SAMA_RDES1_CHECKSUM_IP_TCP | SAMA_RDES1_CHECKSUM_IP_UDP))
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
/* Found a valid one.*/
|
||||||
|
rdp->offset = 0;
|
||||||
|
/* Only with RFCS set */
|
||||||
|
rdp->size = (rdes->rdes1 & SAMA_RDES1_LOF);
|
||||||
|
rdp->physdesc = rdes;
|
||||||
|
if (!(rdes->rdes0 & SAMA_RDES0_WRAP)) {
|
||||||
|
macp->rxptr += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
macp->rxptr = (sama_eth_rx_descriptor_t *)__eth_rd;
|
||||||
|
}
|
||||||
|
osalSysUnlock();
|
||||||
|
return MSG_OK;
|
||||||
|
}
|
||||||
|
/* Invalid frame found, purging.*/
|
||||||
|
rdes->rdes0 &= ~SAMA_RDES0_OWN;
|
||||||
|
if (!(rdes->rdes0 & SAMA_RDES0_WRAP)) {
|
||||||
|
rdes += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rdes = (sama_eth_rx_descriptor_t *)__eth_rd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next descriptor to check.*/
|
||||||
|
macp->rxptr = rdes;
|
||||||
|
|
||||||
|
osalSysUnlock();
|
||||||
|
return MSG_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases a receive descriptor.
|
||||||
|
* @details The descriptor and its buffer are made available for more incoming
|
||||||
|
* frames.
|
||||||
|
*
|
||||||
|
* @param[in] rdp the pointer to the @p MACReceiveDescriptor structure
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) {
|
||||||
|
|
||||||
|
osalDbgAssert(rdp->physdesc->rdes0 & SAMA_RDES0_OWN,
|
||||||
|
"attempt to release descriptor not owned by DMA");
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
|
||||||
|
/* Give buffer back to the Ethernet DMA.*/
|
||||||
|
rdp->physdesc->rdes0 &= ~SAMA_RDES0_OWN;
|
||||||
|
|
||||||
|
/* Wait for the write to rdes0 to go through before resuming the DMA.*/
|
||||||
|
__DSB();
|
||||||
|
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates and returns the link status.
|
||||||
|
*
|
||||||
|
* @param[in] macp pointer to the @p MACDriver object
|
||||||
|
* @return The link status.
|
||||||
|
* @retval true if the link is active.
|
||||||
|
* @retval false if the link is down.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
bool mac_lld_poll_link_status(MACDriver *macp) {
|
||||||
|
uint32_t maccr, bmsr, bmcr;
|
||||||
|
|
||||||
|
maccr = GMAC0->GMAC_NCFGR;
|
||||||
|
|
||||||
|
/* PHY CR and SR registers read.*/
|
||||||
|
(void)mii_read(macp, MII_BMSR);
|
||||||
|
bmsr = mii_read(macp, MII_BMSR);
|
||||||
|
bmcr = mii_read(macp, MII_BMCR);
|
||||||
|
|
||||||
|
/* Check on auto-negotiation mode.*/
|
||||||
|
if (bmcr & BMCR_ANENABLE) {
|
||||||
|
uint32_t lpa;
|
||||||
|
|
||||||
|
/* Auto-negotiation must be finished without faults and link established.*/
|
||||||
|
if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) !=
|
||||||
|
(BMSR_LSTATUS | BMSR_ANEGCOMPLETE))
|
||||||
|
return macp->link_up = false;
|
||||||
|
|
||||||
|
/* Auto-negotiation enabled, checks the LPA register.*/
|
||||||
|
lpa = mii_read(macp, MII_LPA);
|
||||||
|
|
||||||
|
/* Check on link speed.*/
|
||||||
|
if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
|
||||||
|
maccr |= GMAC_NCFGR_SPD;
|
||||||
|
else
|
||||||
|
maccr &= ~GMAC_NCFGR_SPD;
|
||||||
|
|
||||||
|
/* Check on link mode.*/
|
||||||
|
if (lpa & (LPA_10FULL | LPA_100FULL))
|
||||||
|
maccr |= GMAC_NCFGR_FD;
|
||||||
|
else
|
||||||
|
maccr &= ~GMAC_NCFGR_FD;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Link must be established.*/
|
||||||
|
if (!(bmsr & BMSR_LSTATUS))
|
||||||
|
return macp->link_up = false;
|
||||||
|
|
||||||
|
/* Check on link speed.*/
|
||||||
|
if (bmcr & BMCR_SPEED100)
|
||||||
|
maccr |= GMAC_NCFGR_SPD;
|
||||||
|
else
|
||||||
|
maccr &= ~GMAC_NCFGR_SPD;
|
||||||
|
|
||||||
|
/* Check on link mode.*/
|
||||||
|
if (bmcr & BMCR_FULLDPLX)
|
||||||
|
maccr |= GMAC_NCFGR_FD;
|
||||||
|
else
|
||||||
|
maccr &= ~GMAC_NCFGR_FD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Changes the mode in the MAC.*/
|
||||||
|
GMAC0->GMAC_NCFGR = maccr;
|
||||||
|
|
||||||
|
/* Returns the link status.*/
|
||||||
|
return macp->link_up = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes to a transmit descriptor's stream.
|
||||||
|
*
|
||||||
|
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
|
||||||
|
* @param[in] buf pointer to the buffer containing the data to be
|
||||||
|
* written
|
||||||
|
* @param[in] size number of bytes to be written
|
||||||
|
* @return The number of bytes written into the descriptor's
|
||||||
|
* stream, this value can be less than the amount
|
||||||
|
* specified in the parameter @p size if the maximum
|
||||||
|
* frame size is reached.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t size) {
|
||||||
|
|
||||||
|
osalDbgAssert((tdp->physdesc->tdes1 & SAMA_TDES1_USED),
|
||||||
|
"attempt to write descriptor not owned");
|
||||||
|
|
||||||
|
if (size > tdp->size - tdp->offset)
|
||||||
|
size = tdp->size - tdp->offset;
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
memcpy((uint8_t *)(tdp->physdesc->tdes0) + tdp->offset, buf, size);
|
||||||
|
tdp->offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads from a receive descriptor's stream.
|
||||||
|
*
|
||||||
|
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
|
||||||
|
* @param[in] buf pointer to the buffer that will receive the read data
|
||||||
|
* @param[in] size number of bytes to be read
|
||||||
|
* @return The number of bytes read from the descriptor's
|
||||||
|
* stream, this value can be less than the amount
|
||||||
|
* specified in the parameter @p size if there are
|
||||||
|
* no more bytes to read.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t size) {
|
||||||
|
|
||||||
|
osalDbgAssert((rdp->physdesc->rdes0 & SAMA_RDES0_OWN),
|
||||||
|
"attempt to read descriptor not owned");
|
||||||
|
|
||||||
|
if (size > rdp->size - rdp->offset)
|
||||||
|
size = rdp->size - rdp->offset;
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
memcpy(buf, (uint8_t *)(rdp->physdesc->rdes0 & SAMA_RDES0_RBAP_MASK) + rdp->offset, size);
|
||||||
|
rdp->offset += size;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Returns a pointer to the next transmit buffer in the descriptor
|
||||||
|
* chain.
|
||||||
|
* @note The API guarantees that enough buffers can be requested to fill
|
||||||
|
* a whole frame.
|
||||||
|
*
|
||||||
|
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
|
||||||
|
* @param[in] size size of the requested buffer. Specify the frame size
|
||||||
|
* on the first call then scale the value down subtracting
|
||||||
|
* the amount of data already copied into the previous
|
||||||
|
* buffers.
|
||||||
|
* @param[out] sizep pointer to variable receiving the buffer size, it is
|
||||||
|
* zero when the last buffer has already been returned.
|
||||||
|
* Note that a returned size lower than the amount
|
||||||
|
* requested means that more buffers must be requested
|
||||||
|
* in order to fill the frame data entirely.
|
||||||
|
* @return Pointer to the returned buffer.
|
||||||
|
* @retval NULL if the buffer chain has been entirely scanned.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
|
||||||
|
size_t size,
|
||||||
|
size_t *sizep) {
|
||||||
|
|
||||||
|
if (tdp->offset == 0) {
|
||||||
|
*sizep = tdp->size;
|
||||||
|
tdp->offset = size;
|
||||||
|
return (uint8_t *)tdp->physdesc->tdes0;
|
||||||
|
}
|
||||||
|
*sizep = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a pointer to the next receive buffer in the descriptor
|
||||||
|
* chain.
|
||||||
|
* @note The API guarantees that the descriptor chain contains a whole
|
||||||
|
* frame.
|
||||||
|
*
|
||||||
|
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
|
||||||
|
* @param[out] sizep pointer to variable receiving the buffer size, it is
|
||||||
|
* zero when the last buffer has already been returned.
|
||||||
|
* @return Pointer to the returned buffer.
|
||||||
|
* @retval NULL if the buffer chain has been entirely scanned.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
|
||||||
|
size_t *sizep) {
|
||||||
|
|
||||||
|
if (rdp->size > 0) {
|
||||||
|
*sizep = rdp->size;
|
||||||
|
rdp->offset = rdp->size;
|
||||||
|
rdp->size = 0;
|
||||||
|
return (uint8_t *)rdp->physdesc->rdes0 & SAMA_RDES0_RBAP_MASK;
|
||||||
|
}
|
||||||
|
*sizep = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif /* MAC_USE_ZERO_COPY */
|
||||||
|
|
||||||
|
#endif /* HAL_USE_MAC */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,329 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file MACv1/hal_mac_lld.h
|
||||||
|
* @brief SAMA low level MAC driver header.
|
||||||
|
*
|
||||||
|
* @addtogroup MAC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HAL_MAC_LLD_H
|
||||||
|
#define HAL_MAC_LLD_H
|
||||||
|
|
||||||
|
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This implementation supports the zero-copy mode API.
|
||||||
|
*/
|
||||||
|
#define MAC_SUPPORTS_ZERO_COPY FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name RDES0 constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define SAMA_RDES0_RBAP_MASK 0xFFFFFFFC
|
||||||
|
#define SAMA_RDES0_WRAP 0x00000002
|
||||||
|
#define SAMA_RDES0_OWN 0x00000001
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name RDES1 constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define SAMA_RDES1_BROADCAST 0x80000000
|
||||||
|
#define SAMA_RDES1_MULTICAST_HASH 0x40000000
|
||||||
|
#define SAMA_RDES1_UNICAST_HASH 0x20000000
|
||||||
|
#define SAMA_RDES1_ADDR_REG_MATCH 0x08000000
|
||||||
|
#define SAMA_RDES1_ADDR_REG 0x06000000
|
||||||
|
#define SAMA_RDES1_ID_REG_MATCH 0x01000000
|
||||||
|
#define SAMA_RDES1_SNAP_ENCODED 0x01000000
|
||||||
|
#define SAMA_RDES1_ID_REG 0x00C00000
|
||||||
|
#define SAMA_RDES1_CHECKSUM_IP_TCP 0x00800000
|
||||||
|
#define SAMA_RDES1_CHECKSUM_IP_UDP 0x00C00000
|
||||||
|
#define SAMA_RDES1_CHECKSUM_IP 0x00400000
|
||||||
|
#define SAMA_RDES1_VLAN_TAG_DET 0x00200000
|
||||||
|
#define SAMA_RDES1_PRIOR_TAG_DET 0x00100000
|
||||||
|
#define SAMA_RDES1_VLAN_PRIOR 0x000E0000
|
||||||
|
#define SAMA_RDES1_CFI 0x00010000
|
||||||
|
#define SAMA_RDES1_EOF 0x00008000
|
||||||
|
#define SAMA_RDES1_SOF 0x00004000
|
||||||
|
#define SAMA_RDES1_ADD_BIT_LOF 0x00002000
|
||||||
|
#define SAMA_RDES1_BAD_FCS 0x00002000
|
||||||
|
#define SAMA_RDES1_LOF 0x00001FFF
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name TDES0 constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define SAMA_TDES0_BYTE_ADDR 0xFFFFFFFF
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name TDES1 constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define SAMA_TDES1_USED 0x80000000
|
||||||
|
#define SAMA_TDES1_WRAP 0x40000000
|
||||||
|
#define SAMA_TDES1_RLE_TX_ERR 0x20000000
|
||||||
|
#define SAMA_TDES1_LOCKED 0x10000000 /* NOTE: Pseudo flag. */
|
||||||
|
#define SAMA_TDES1_AHB_TX_ERR 0x08000000
|
||||||
|
#define SAMA_TDES1_LC_TX_ERR 0x04000000
|
||||||
|
#define SAMA_TDES1_CHECKSUM_ERR 0x00700000
|
||||||
|
#define SAMA_TDES1_CRC 0x00010000
|
||||||
|
#define SAMA_TDES1_LAST_BUFF 0x00008000
|
||||||
|
#define SAMA_TDES1_LENGTH_BUFF 0x00003FFF
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver pre-compile time settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Configuration options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief Number of available transmit buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_TRANSMIT_BUFFERS 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of available receive buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_RECEIVE_BUFFERS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum supported frame size.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_BUFFERS_SIZE 1536
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PHY detection timeout.
|
||||||
|
* @details Timeout for PHY address detection, the scan for a PHY is performed
|
||||||
|
* the specified number of times before invoking the failure handler.
|
||||||
|
* This setting applies only if the PHY address is not explicitly
|
||||||
|
* set in the board header file using @p BOARD_PHY_ADDRESS. A zero
|
||||||
|
* value disables the timeout and a single search is performed.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_PHY_TIMEOUT 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change the PHY power state inside the driver.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_ETH0_CHANGE_PHY_STATE) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_ETH0_CHANGE_PHY_STATE TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ETHD0 interrupt priority level setting.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_ETH0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_ETH0_IRQ_PRIORITY 7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IP checksum offload.
|
||||||
|
* @details The following modes are available:
|
||||||
|
* - 0 Function disabled.
|
||||||
|
* - 1 Only IP header checksum calculation and insertion are enabled.
|
||||||
|
*/
|
||||||
|
#if !defined(SAMA_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__)
|
||||||
|
#define SAMA_MAC_IP_CHECKSUM_OFFLOAD 1
|
||||||
|
#endif
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of an SAMA Ethernet receive descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t rdes0;
|
||||||
|
volatile uint32_t rdes1;
|
||||||
|
} sama_eth_rx_descriptor_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of an SAMA Ethernet transmit descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t tdes0;
|
||||||
|
volatile uint32_t tdes1;
|
||||||
|
} sama_eth_tx_descriptor_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Driver configuration structure.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief MAC address.
|
||||||
|
*/
|
||||||
|
uint8_t *mac_address;
|
||||||
|
/* End of the mandatory fields.*/
|
||||||
|
} MACConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing a MAC driver.
|
||||||
|
*/
|
||||||
|
struct MACDriver {
|
||||||
|
/**
|
||||||
|
* @brief Driver state.
|
||||||
|
*/
|
||||||
|
macstate_t state;
|
||||||
|
/**
|
||||||
|
* @brief Current configuration data.
|
||||||
|
*/
|
||||||
|
const MACConfig *config;
|
||||||
|
/**
|
||||||
|
* @brief Transmit semaphore.
|
||||||
|
*/
|
||||||
|
threads_queue_t tdqueue;
|
||||||
|
/**
|
||||||
|
* @brief Receive semaphore.
|
||||||
|
*/
|
||||||
|
threads_queue_t rdqueue;
|
||||||
|
#if MAC_USE_EVENTS || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Receive event.
|
||||||
|
*/
|
||||||
|
event_source_t rdevent;
|
||||||
|
#endif
|
||||||
|
/* End of the mandatory fields.*/
|
||||||
|
/**
|
||||||
|
* @brief Link status flag.
|
||||||
|
*/
|
||||||
|
bool link_up;
|
||||||
|
/**
|
||||||
|
* @brief PHY address (pre shifted).
|
||||||
|
*/
|
||||||
|
uint32_t phyaddr;
|
||||||
|
/**
|
||||||
|
* @brief Receive next frame pointer.
|
||||||
|
*/
|
||||||
|
sama_eth_rx_descriptor_t *rxptr;
|
||||||
|
/**
|
||||||
|
* @brief Transmit next frame pointer.
|
||||||
|
*/
|
||||||
|
sama_eth_tx_descriptor_t *txptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing a transmit descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief Current write offset.
|
||||||
|
*/
|
||||||
|
size_t offset;
|
||||||
|
/**
|
||||||
|
* @brief Available space size.
|
||||||
|
*/
|
||||||
|
size_t size;
|
||||||
|
/* End of the mandatory fields.*/
|
||||||
|
/**
|
||||||
|
* @brief Pointer to the physical descriptor.
|
||||||
|
*/
|
||||||
|
sama_eth_tx_descriptor_t *physdesc;
|
||||||
|
} MACTransmitDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing a receive descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief Current read offset.
|
||||||
|
*/
|
||||||
|
size_t offset;
|
||||||
|
/**
|
||||||
|
* @brief Available data size.
|
||||||
|
*/
|
||||||
|
size_t size;
|
||||||
|
/* End of the mandatory fields.*/
|
||||||
|
/**
|
||||||
|
* @brief Pointer to the physical descriptor.
|
||||||
|
*/
|
||||||
|
sama_eth_rx_descriptor_t *physdesc;
|
||||||
|
} MACReceiveDescriptor;
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if !defined(__DOXYGEN__)
|
||||||
|
extern MACDriver ETHD0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void mii_write(MACDriver *macp, uint32_t reg, uint32_t value);
|
||||||
|
uint32_t mii_read(MACDriver *macp, uint32_t reg);
|
||||||
|
void mac_lld_init(void);
|
||||||
|
void mac_lld_start(MACDriver *macp);
|
||||||
|
void mac_lld_stop(MACDriver *macp);
|
||||||
|
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
|
||||||
|
MACTransmitDescriptor *tdp);
|
||||||
|
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp);
|
||||||
|
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
|
||||||
|
MACReceiveDescriptor *rdp);
|
||||||
|
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp);
|
||||||
|
bool mac_lld_poll_link_status(MACDriver *macp);
|
||||||
|
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t size);
|
||||||
|
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t size);
|
||||||
|
#if MAC_USE_ZERO_COPY
|
||||||
|
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
|
||||||
|
size_t size,
|
||||||
|
size_t *sizep);
|
||||||
|
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
|
||||||
|
size_t *sizep);
|
||||||
|
#endif /* MAC_USE_ZERO_COPY */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* HAL_USE_MAC */
|
||||||
|
|
||||||
|
#endif /* HAL_MAC_LLD_H */
|
||||||
|
|
||||||
|
/** @} */
|
Loading…
Reference in New Issue