diff options
Diffstat (limited to 'os')
| -rw-r--r-- | os/hal/ports/SAMA/LLD/MACv1/driver.mk | 9 | ||||
| -rw-r--r-- | os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c | 826 | ||||
| -rw-r--r-- | os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.h | 329 | 
3 files changed, 1164 insertions, 0 deletions
| diff --git a/os/hal/ports/SAMA/LLD/MACv1/driver.mk b/os/hal/ports/SAMA/LLD/MACv1/driver.mk new file mode 100644 index 000000000..2d9c51db8 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/MACv1/driver.mk @@ -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
 diff --git a/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c b/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c new file mode 100644 index 000000000..3ee457b8c --- /dev/null +++ b/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c @@ -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 */
 +
 +/** @} */
 diff --git a/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.h b/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.h new file mode 100644 index 000000000..958612a6d --- /dev/null +++ b/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.h @@ -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 */
 +
 +/** @} */
 | 
