diff --git a/boards/same54-xpro/Makefile.dep b/boards/same54-xpro/Makefile.dep index 3c35960fac14..e8d751a43b05 100644 --- a/boards/same54-xpro/Makefile.dep +++ b/boards/same54-xpro/Makefile.dep @@ -10,3 +10,8 @@ ifneq (,$(filter mtd,$(USEMODULE))) FEATURES_REQUIRED += periph_spi_on_qspi USEMODULE += mtd_spi_nor endif + +# enables sam0_eth as default network device +ifneq (,$(filter netdev_default,$(USEMODULE))) + USEMODULE += sam0_eth +endif diff --git a/boards/same54-xpro/Makefile.features b/boards/same54-xpro/Makefile.features index 7bf9dac809b3..3d0b725045de 100644 --- a/boards/same54-xpro/Makefile.features +++ b/boards/same54-xpro/Makefile.features @@ -3,6 +3,7 @@ CPU_MODEL = same54p20a # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_dac +FEATURES_PROVIDED += periph_eth FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt diff --git a/boards/same54-xpro/include/periph_conf.h b/boards/same54-xpro/include/periph_conf.h index 301b1da5e8ca..10aad210c73d 100644 --- a/boards/same54-xpro/include/periph_conf.h +++ b/boards/same54-xpro/include/periph_conf.h @@ -361,6 +361,28 @@ static const adc_conf_chan_t adc_channels[] = { #define DAC_VREF DAC_CTRLB_REFSEL_VREFPU /** @} */ +/** + * @name Ethernet peripheral configuration + * @{ + */ +static const sam0_common_gmac_config_t sam_gmac_config[] = { + { + .dev = GMAC, + .refclk = GPIO_PIN(PA, 14), + .txen = GPIO_PIN(PA, 17), + .txd0 = GPIO_PIN(PA, 18), + .txd1 = GPIO_PIN(PA, 19), + .crsdv = GPIO_PIN(PC, 20), + .rxd0 = GPIO_PIN(PA, 13), + .rxd1 = GPIO_PIN(PA, 12), + .rxer = GPIO_PIN(PA, 15), + .mdc = GPIO_PIN(PC, 11), + .mdio = GPIO_PIN(PC, 12), + .rst_pin = GPIO_PIN(PC, 21), + .int_pin = GPIO_PIN(PD, 12), + } +}; + #ifdef __cplusplus } #endif diff --git a/cpu/sam0_common/Makefile b/cpu/sam0_common/Makefile index e09377cd1e39..3824d9e978f1 100644 --- a/cpu/sam0_common/Makefile +++ b/cpu/sam0_common/Makefile @@ -1,3 +1,7 @@ DIRS = periph +ifneq (, $(filter sam0_eth, $(USEMODULE))) + DIRS += sam0_eth +endif + include $(RIOTBASE)/Makefile.base diff --git a/cpu/sam0_common/Makefile.dep b/cpu/sam0_common/Makefile.dep index 183c361c72ee..276bd6531cad 100644 --- a/cpu/sam0_common/Makefile.dep +++ b/cpu/sam0_common/Makefile.dep @@ -12,4 +12,11 @@ USEMODULE += pm_layered # include sam0 common periph drivers USEMODULE += sam0_common_periph +ifneq (,$(filter sam0_eth,$(USEMODULE))) + USEMODULE += netdev_eth + USEMODULE += netopt + USEMODULE += xtimer + USEMODULE += iolist + FEATURES_REQUIRED += periph_eth +endif include $(RIOTCPU)/cortexm_common/Makefile.dep diff --git a/cpu/sam0_common/Makefile.include b/cpu/sam0_common/Makefile.include index 8a15929c2b59..01803bc05863 100644 --- a/cpu/sam0_common/Makefile.include +++ b/cpu/sam0_common/Makefile.include @@ -31,5 +31,9 @@ LINKER_SCRIPT ?= cortexm.ld INCLUDES += -I$(RIOTCPU)/sam0_common/include +ifneq (,$(filter sam0_eth,$(USEMODULE))) + INCLUDES += -I$(RIOTCPU)/sam0_common/sam0_eth/ +endif + PSEUDOMODULES += periph_rtc PSEUDOMODULES += periph_rtt diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index d6310e61231d..2f3203515b49 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -141,6 +141,7 @@ typedef enum { GPIO_MUX_F = 0x5, /**< select peripheral function F */ GPIO_MUX_G = 0x6, /**< select peripheral function G */ GPIO_MUX_H = 0x7, /**< select peripheral function H */ + GPIO_MUX_L = 0xb, } gpio_mux_t; #endif @@ -767,6 +768,48 @@ typedef struct { uint32_t muxpos; /**< ADC channel pin multiplexer value */ } adc_conf_chan_t; +/** + * @name Ethernet peripheral parameters + * @{ + */ +#ifndef ETH_RX_BUFFER_COUNT +#define ETH_RX_BUFFER_COUNT (4) +#endif + +#ifndef ETH_TX_BUFFER_COUNT +#define ETH_TX_BUFFER_COUNT (4) +#endif + +#ifndef ETH_RX_BUFFER_SIZE +#define ETH_RX_BUFFER_SIZE (1536) +#endif + +#ifndef ETH_TX_BUFFER_SIZE +#define ETH_TX_BUFFER_SIZE (1536) +#endif +/** @} */ + +/** + * @brief Ethernet parameters struct + */ +#if defined(GMAC_INST_NUM) || defined(DOXYGEN) +typedef struct { + Gmac *dev; /**< ptr to the device registers */ + gpio_t refclk; /**< REFCLK gpio */ + gpio_t txen; /**< TXEN gpio */ + gpio_t txd0; /**< TXD0 gpio */ + gpio_t txd1; /**< TXD1 gpio */ + gpio_t crsdv; /**< CRSDV gpio */ + gpio_t rxd0; /**< RXD0 gpio */ + gpio_t rxd1; /**< RXD1 gpio */ + gpio_t rxer; /**< RXER gpio */ + gpio_t mdc; /**< MII interface, clock gpio */ + gpio_t mdio; /**< MII interface, data gpio */ + gpio_t rst_pin; /**< PHY reset gpio */ + gpio_t int_pin; /**< PHY interrupt gpio */ +} sam0_common_gmac_config_t; +#endif + /** * @brief USB peripheral parameters */ diff --git a/cpu/sam0_common/periph/eth.c b/cpu/sam0_common/periph/eth.c new file mode 100644 index 000000000000..46cd5dd6078f --- /dev/null +++ b/cpu/sam0_common/periph/eth.c @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2020 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup cpu_sam0_common + * @{ + * + * @file + * @brief Low-level Ethernet driver implementation + * + * @author Dylan Laduranty + * + * @} + */ + +#include "iolist.h" +#include "net/eui48.h" +#include "net/ethernet.h" +#include "net/netdev/eth.h" + +#include "periph/gpio.h" + +#include "sam0_eth_netdev.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" +#include "log.h" + +#include + +/* Internal helpers */ +#define PHY_READ_OP 0x02 +#define PHY_WRITE_OP 0x01 + +/* Internal RX/TX descriptors */ +#define DESC_RX_ADDR_OWNSHP 1 +#define DESC_RX_ADDR_WRAP 2 +#define DESC_RX_ADDR_ADDR_MASK 0xFFFFFFFC + +#define DESC_RX_STATUS_FRAME_LEN_MASK 0x1FFF + +#define DESC_RX_STATUS_FCS_MASK (1ul << 13) +#define DESC_RX_STATUS_STA_FRAME (1ul << 14) +#define DESC_RX_STATUS_END_FRAME (1ul << 15) +#define DESC_RX_STATUS_CFI (1ul << 16) +#define DESC_RX_STATUS_VLAN_PRIO (1ul << 17) || (1ul << 18) || (1ul << 19) +#define DESC_RX_STATUS_PRIO_TAG (1ul << 20) +#define DESC_RX_STATUS_VLAN_TAG (1ul << 21) +#define DESC_RX_STATUS_TYPE_ID (1ul << 22) || (1ul << 23) +#define DESC_RX_STATUS_CHKSUM (1ul << 24) +#define DESC_RX_STATUS_SPEC_ADDR (1ul << 25) || (1ul << 26) +#define DESC_RX_STATUS_SPEC_TAG (1ul << 27) +#define DESC_RX_STATUS_UNIHASH (1ul << 29) +#define DESC_RX_STATUS_MULTIHASH (1ul << 30) +#define DESC_RX_STATUS_BROADCAST (1ul << 31) + +#define DESC_TX_STATUS_LEN_MASK 0x3FFF +#define DESC_TX_STATUS_LAST_BUF (1ul << 15) +#define DESC_TX_STATUS_CRC (1ul << 16) +#define DESC_TX_STATUS_CHKSUM (1ul << 20) || (1ul << 21) || (1ul << 22) +#define DESC_TX_STATUS_LATE_COL (1ul << 26) +#define DESC_TX_STATUS_TX_ERROR (1ul << 27) +#define DESC_TX_STATUS_RETRY (1ul << 29) +#define DESC_TX_STATUS_WRAP (1ul << 30) +#define DESC_TX_STATUS_USED (1ul << 31) + +struct eth_buf_desc { + uint32_t address; + uint32_t status; +}; + +/* GMAC buffer descriptors */ +#define GMAC_DESC_ALIGNMENT 8 +#define GMAC_BUF_ALIGNMENT 32 +static struct eth_buf_desc rx_desc[ETH_RX_BUFFER_COUNT] __attribute__((aligned(GMAC_DESC_ALIGNMENT))); +static struct eth_buf_desc tx_desc[ETH_TX_BUFFER_COUNT] __attribute__((aligned(GMAC_DESC_ALIGNMENT))); + +static struct eth_buf_desc *rx_curr; +static struct eth_buf_desc *tx_curr; + +/* Declare our own indexes to point to a RX/TX buffer descriptor. + GMAC IP have its own indexes on its side */ +static uint8_t tx_idx; +static uint8_t rx_idx; + +static uint8_t rx_buf[ETH_RX_BUFFER_COUNT][ETH_RX_BUFFER_SIZE] __attribute__((aligned(GMAC_BUF_ALIGNMENT))); +static uint8_t tx_buf[ETH_TX_BUFFER_COUNT][ETH_TX_BUFFER_SIZE] __attribute__((aligned(GMAC_BUF_ALIGNMENT))); + +static void _init_desc_buf(void) +{ + int i; + /* Initialize RX buffer descriptors */ + for (i=0; i < ETH_RX_BUFFER_COUNT; i++) { + rx_desc[i].address = ((uint32_t) (rx_buf[i]) & DESC_RX_ADDR_ADDR_MASK); + } + /* Set WRAP flag to indicate last buffer */ + rx_desc[i-1].address |= DESC_RX_ADDR_WRAP; + rx_curr = &rx_desc[0]; + /* Initialize TX buffer descriptors */ + for (i=0; i < ETH_TX_BUFFER_COUNT; i++) { + tx_desc[i].address = (uint32_t) tx_buf[i]; + } + /* Set WRAP flag to indicate last buffer */ + tx_desc[i-1].status |= DESC_TX_STATUS_WRAP; + tx_curr = &tx_desc[0]; + /* Setup buffers index */ + rx_idx = 0; + tx_idx = 0; + /* Store RX buffer descriptor list */ + GMAC->RBQB.reg = (uint32_t) rx_desc; + /* Store TX buffer descriptor list */ + GMAC->TBQB.reg = (uint32_t) tx_desc; +} + +int sam0_read_phy(uint8_t phy, uint8_t addr) +{ + GMAC->MAN.reg = GMAC_MAN_REGA(addr) | GMAC_MAN_PHYA(phy) + | GMAC_MAN_CLTTO | GMAC_MAN_WTN(0x2) + | GMAC_MAN_OP(PHY_READ_OP); + + /* Wait for operation completion */ + while (!GMAC->NSR.bit.IDLE) {} + /* return content of shift register */ + return (GMAC->MAN.reg & GMAC_MAN_DATA_Msk); +} + +void sam0_write_phy(uint8_t phy, uint8_t addr, uint16_t data) +{ + GMAC->MAN.reg = GMAC_MAN_REGA(addr) | GMAC_MAN_PHYA(phy) + | GMAC_MAN_WTN(0x2) | GMAC_MAN_OP(PHY_WRITE_OP) + | GMAC_MAN_CLTTO | GMAC_MAN_DATA(data); + + /* Wait for operation completion */ + while (!GMAC->NSR.bit.IDLE) {} +} + +void sam0_eth_set_mac(const eui48_t *mac) +{ + GMAC->Sa[0].SAT.reg = ((mac->uint8[5] << 8) | mac->uint8[4]); + GMAC->Sa[0].SAB.reg = ((mac->uint8[3] << 24) | (mac->uint8[2] << 16) + | (mac->uint8[1] << 8) | mac->uint8[0]); +} + +void sam0_eth_get_mac(eui48_t *out) +{ + out->uint8[5] = (GMAC->Sa[0].SAT.reg >> 8); + out->uint8[4] = (GMAC->Sa[0].SAT.reg); + out->uint8[3] = (GMAC->Sa[0].SAB.reg >> 24); + out->uint8[2] = (GMAC->Sa[0].SAB.reg >> 16); + out->uint8[1] = (GMAC->Sa[0].SAB.reg >> 8); + out->uint8[0] = (GMAC->Sa[0].SAB.reg); +} + +int sam0_eth_send(const struct iolist *iolist) +{ + unsigned len = iolist_size(iolist); + unsigned tx_len = 0; + tx_curr = &tx_desc[tx_idx]; + + /* load packet data into TX buffer */ + for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) { + if (tx_len + iol->iol_len > ETHERNET_MAX_LEN) { + return -EBUSY; + } + if (iol->iol_len) { + memcpy ((uint32_t*)(tx_curr->address + tx_len), iol->iol_base, iol->iol_len); + tx_len += iol->iol_len; + } + } + if (len == tx_len) { + /* Clear and set the frame size */ + tx_curr->status &= ~DESC_TX_STATUS_LEN_MASK; + tx_curr->status |= (len & DESC_TX_STATUS_LEN_MASK); + /* Indicate this is the last buffer and the frame is ready */ + tx_curr->status |= DESC_TX_STATUS_LAST_BUF | DESC_TX_STATUS_USED; + /* Prepare next buffer index */ + tx_idx = (tx_idx < ETH_TX_BUFFER_COUNT-1) ? tx_idx+1 : 0; + __DSB(); + tx_curr->status &= ~DESC_TX_STATUS_USED; + /* Start transmission */ + GMAC->NCR.reg |= GMAC_NCR_TSTART; + /* Set the next buffer */ + tx_curr = &tx_desc[tx_idx]; + } + else { + DEBUG("Mismatch TX len, abort send\n"); + } + return len; +} + +static int _try_receive(char* data, int max_len, int block) +{ + (void)block; + unsigned rxlen = 0; + uint16_t idx = rx_idx; + /* Ensure we are at the beginning of the new frame */ + while (!(rx_curr->address & DESC_RX_ADDR_OWNSHP) && (rx_curr->status & DESC_RX_STATUS_STA_FRAME)) {} + + for (unsigned cpt=0; cpt < ETH_RX_BUFFER_COUNT; cpt++) { + /* Get the length of the received frame */ + unsigned len = (rx_curr->status & DESC_RX_STATUS_FRAME_LEN_MASK); + + /* Only copy data if the stack requested it, otherwise return the length + of the next frame if available */ + if (max_len) { + /* If buffer available, copy data into it */ + if (data) { + memcpy(&data[rxlen], rx_buf[idx], len); + } + /* Tell the GMAC IP that we don't need this frame anymore */ + rx_curr->address &= ~DESC_RX_ADDR_OWNSHP; + } + + rxlen += len; + + if (rx_curr->status & DESC_RX_STATUS_END_FRAME) { + /* We reach the end of frame, leave the loop */ + break; + } + /* Prepare next buffer */ + idx = (idx + 1) % ETH_RX_BUFFER_COUNT; + rx_curr = &rx_desc[idx]; + + } + /* restore the previous index if packets were not released */ + if (!max_len) { + rx_curr = &rx_desc[rx_idx]; + } + /* Point to the next buffer as GMAC IP will likely used it + to store the next frame */ + else { + rx_idx = (idx+1) % ETH_RX_BUFFER_COUNT; + rx_curr = &rx_desc[rx_idx]; + } + + return rxlen; +} + +int sam0_eth_receive_blocking(char *data, unsigned max_len) +{ + return _try_receive(data, max_len, 1); +} + +static void _enable_clock(void) +{ + /* Enable GMAC clocks */ + MCLK->AHBMASK.reg |= MCLK_AHBMASK_GMAC; + MCLK->APBCMASK.reg |= MCLK_APBCMASK_GMAC; +} + +int sam0_eth_init(void) +{ + /* Enable clocks */ + _enable_clock(); + /* Initialize GPIOs */ + gpio_init_mux(sam_gmac_config[0].refclk, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].txen, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].txd0, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].txd1, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].crsdv, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].rxd0, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].rxd1, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].rxer, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].mdc, GPIO_MUX_L); + gpio_init_mux(sam_gmac_config[0].mdio, GPIO_MUX_L); + /* PHY reset */ + gpio_init(sam_gmac_config[0].rst_pin, GPIO_OUT); + gpio_clear(sam_gmac_config[0].rst_pin); + + /* reset buffers */ + memset(rx_buf, 0, sizeof(rx_buf)); + memset(tx_buf, 0, sizeof(tx_buf)); + memset(rx_desc, 0, sizeof(rx_desc)); + memset(tx_desc, 0, sizeof(tx_desc)); + + /* Enable PHY */ + gpio_set(sam_gmac_config[0].rst_pin); + + /* Initialize buffers descriptor */ + _init_desc_buf(); + /* Disable RX and TX */ + GMAC->NCR.reg &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN); + /* Enable Port Management */ + GMAC->NCR.reg |= GMAC_NCR_MPE; + /* TODO: Implements MII, default to RMII */ + GMAC->UR.reg = 0; + /* disable all interrupts */ + GMAC->IDR.reg = 0xFFFFFFFF; + /* clear flags */ + GMAC->RSR.reg = GMAC_RSR_HNO | GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA; + /* Enable needed interrupts */ + GMAC->IER.reg = GMAC_IER_RCOMP; + + /* Set TxBase-100-FD by default */ + /* TODO: implement auto negotiation */ + GMAC->NCFGR.reg |= (GMAC_NCFGR_SPD | GMAC_NCFGR_FD | GMAC_NCFGR_MTIHEN | + GMAC_NCFGR_RXCOEN | GMAC_NCFGR_MAXFS | GMAC_NCFGR_CAF | + GMAC_NCFGR_LFERD | GMAC_NCFGR_RFCS | GMAC_NCFGR_CLK(3)); + + /* Enable all multicast addresses */ + GMAC->HRB.reg = 0xffffffff; + GMAC->HRT.reg = 0xffffffff; + + /* Set DMA receive buffer size to 1536 bytes */ + GMAC->DCFGR.reg |= GMAC_DCFGR_DRBS(0x18); + /* Enable PHY */ + gpio_set(sam_gmac_config[0].rst_pin); + /* Enable IRQ */ + NVIC_EnableIRQ(GMAC_IRQn); + /* Enable both receiver and transmitter */ + GMAC->NCR.reg |= GMAC_NCR_TXEN | GMAC_NCR_RXEN; + + return 0; +} diff --git a/cpu/sam0_common/sam0_eth/Makefile b/cpu/sam0_common/sam0_eth/Makefile new file mode 100644 index 000000000000..0b76ba4d73fa --- /dev/null +++ b/cpu/sam0_common/sam0_eth/Makefile @@ -0,0 +1,3 @@ +MODULE=sam0_eth + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/sam0_common/sam0_eth/eth-netdev.c b/cpu/sam0_common/sam0_eth/eth-netdev.c new file mode 100644 index 000000000000..6592478f3360 --- /dev/null +++ b/cpu/sam0_common/sam0_eth/eth-netdev.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2020 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup cpu_sam0_common + * @{ + * + * @file + * @brief Low-level Ethernet driver implementation + * + * @author Dylan Laduranty + * + * @} + */ +#include + +#include "iolist.h" +#include "net/gnrc/netif/ethernet.h" +#include "net/gnrc.h" +#include "net/ethernet.h" +#include "net/netdev/eth.h" +#include "net/eui_provider.h" + +#include "periph/gpio.h" + +#include "sam0_eth_netdev.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" +#include "log.h" + +/* Internal helpers */ +extern int sam0_eth_init(void); +extern int sam0_eth_send(const struct iolist *iolist); +extern int sam0_eth_receive_blocking(char *data, unsigned max_len); +extern void sam0_eth_set_mac(const eui48_t *mac); +extern void sam0_eth_get_mac(char *out); + +/* SAM0 CPUs only have one GMAC IP, so it is safe to +statically defines one in this file */ +static sam0_eth_netdev_t _sam0_eth_dev; + +static int _sam0_eth_init(netdev_t *netdev) +{ + sam0_eth_init(); + eui48_t hwaddr; + netdev_eui48_get(netdev, &hwaddr); + sam0_eth_set_mac(&hwaddr); + return 0; +} + +static void _sam0_eth_isr(netdev_t *netdev) +{ + netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); + return; +} + +static int _sam0_eth_recv(netdev_t *netdev, void *buf, size_t len, void *info) +{ + (void)info; + (void)netdev; + unsigned ret = sam0_eth_receive_blocking((char *)buf, len); + return ret; +} + +static int _sam0_eth_send(netdev_t *netdev, const iolist_t *iolist) +{ + int ret; + + netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED); + ret = sam0_eth_send(iolist); + if (ret == -EOVERFLOW) { + /* TODO: use a specific netdev callback here ? */ + return -EOVERFLOW; + } + netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); + return ret; +} + +static int _sam0_eth_get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len) +{ + int res = -1; + + switch (opt) { + case NETOPT_ADDRESS: + assert(max_len >= ETHERNET_ADDR_LEN); + sam0_eth_get_mac((char *)val); + res = ETHERNET_ADDR_LEN; + break; + default: + res = netdev_eth_get(netdev, opt, val, max_len); + break; + } + + return res; +} + +static int _sam0_eth_set(netdev_t *netdev, netopt_t opt, const void *val, size_t max_len) +{ + int res = -1; + + switch (opt) { + case NETOPT_ADDRESS: + assert(max_len >= ETHERNET_ADDR_LEN); + sam0_eth_set_mac((eui48_t *)val); + res = ETHERNET_ADDR_LEN; + break; + default: + res = netdev_eth_set(netdev, opt, val, max_len); + break; + } + + return res; +} + +static const netdev_driver_t _sam0_eth_driver = +{ + .send = _sam0_eth_send, + .recv = _sam0_eth_recv, + .init = _sam0_eth_init, + .isr = _sam0_eth_isr, + .get = _sam0_eth_get, + .set = _sam0_eth_set, +}; + +void sam0_eth_setup(netdev_t* netdev) +{ + + DEBUG_PUTS("[sam0_eth]: initializing SAM0 Ethernet MAC (GMAC) device"); + + _sam0_eth_dev.netdev = netdev; + /* set the netdev driver */ + netdev->driver = &_sam0_eth_driver; + /* Register SAM0 Ethernet to netdev */ + netdev_register(netdev, NETDEV_SAM0_ETH, 0); +} + +/* TODO: rework the whole isr management... */ +void isr_gmac(void) +{ + uint32_t isr; + uint32_t tsr; + uint32_t rsr; + + isr = GMAC->ISR.reg; + tsr = GMAC->TSR.reg; + rsr = GMAC->RSR.reg; + + if (rsr == GMAC_RSR_REC) { + netdev_trigger_event_isr(_sam0_eth_dev.netdev); + } + + GMAC->TSR.reg = tsr; + GMAC->RSR.reg = rsr; + GMAC->ISR.reg = isr; + + cortexm_isr_end(); +} diff --git a/cpu/sam0_common/sam0_eth/sam0_eth_netdev.h b/cpu/sam0_common/sam0_eth/sam0_eth_netdev.h new file mode 100644 index 000000000000..54dd7c75ddbf --- /dev/null +++ b/cpu/sam0_common/sam0_eth/sam0_eth_netdev.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 Dylan Laduranty + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cpu_sam0_common_eth sam0 Ethernet peripheral + * @ingroup cpu_sam0_common + * @{ + * + * @file + * @brief Netdev interface for the SAM0 Ethernet GMAC peripheral + * + * @author Dylan Laduranty + */ + +#ifndef SAM0_ETH_NETDEV_H +#define SAM0_ETH_NETDEV_H + +#include + +#include "net/ethernet.h" +#include "net/netdev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const netdev_driver_t sam0_eth_driver; + +/** + * @brief Device descriptor for SAM0-ETH devices + */ +typedef struct { + netdev_t* netdev; /**< netdev parent struct */ +} sam0_eth_netdev_t; + +/** + * @brief Setup SAM0 Ethernet peripheral + * + * @param[in] dev Pointer to the SAM0 Ethernet netdev struct + * + */ + +void sam0_eth_netdev_setup(sam0_eth_netdev_t* dev); + +#ifdef __cplusplus +} +#endif + +#endif /* SAM0_ETH_NETDEV_H */ +/** @} */ diff --git a/cpu/samd5x/Kconfig b/cpu/samd5x/Kconfig index 5ebb1052dd1e..a353bf5af53f 100644 --- a/cpu/samd5x/Kconfig +++ b/cpu/samd5x/Kconfig @@ -12,6 +12,7 @@ config CPU_COMMON_SAMD5X select HAS_BACKUP_RAM select HAS_CORTEXM_MPU select HAS_CPU_SAMD5X + select HAS_PERIPH_ETH select HAS_PERIPH_GPIO_TAMPER_WAKE select HAS_PERIPH_HWRNG select HAS_PERIPH_SPI_ON_QSPI diff --git a/drivers/include/net/netdev.h b/drivers/include/net/netdev.h index 21dd89c31766..11af4087e0fc 100644 --- a/drivers/include/net/netdev.h +++ b/drivers/include/net/netdev.h @@ -293,6 +293,7 @@ typedef enum { NETDEV_STM32_ETH, NETDEV_CC110X, NETDEV_SX127X, + NETDEV_SAM0_ETH, /* add more if needed */ } netdev_type_t; /** @} */ diff --git a/examples/default/Makefile b/examples/default/Makefile index 3bf74a5d8729..5e371bec9543 100644 --- a/examples/default/Makefile +++ b/examples/default/Makefile @@ -39,7 +39,7 @@ BOARD_PROVIDES_NETIF := acd52832 adafruit-clue airfy-beacon atmega256rfr2-xpro \ derfmega128 derfmega256 hamilton iotlab-m3 iotlab-a8-m3 lobaro-lorabox lsn50 mulle microbit msba2 \ microduino-corerf native nrf51dk nrf51dongle nrf52dk nrf52840dk nrf52840-mdk nrf6310 \ nucleo-f207zg nucleo-f767zi openmote-b openmote-cc2538 pba-d-01-kw2x remote-pa \ - remote-reva ruuvitag samr21-xpro samr30-xpro spark-core telosb thingy52 yunjia-nrf51822 z1 \ + remote-reva ruuvitag same54-xpro samr21-xpro samr30-xpro spark-core telosb thingy52 yunjia-nrf51822 z1 \ frdm-kw41z phynode-kw41z usb-kw41z openlabs-kw41z-mini openlabs-kw41z-mini-256kib ifneq (,$(filter $(BOARD),$(BOARD_PROVIDES_NETIF))) diff --git a/sys/net/gnrc/netif/init_devs/auto_init_sam0_eth.c b/sys/net/gnrc/netif/init_devs/auto_init_sam0_eth.c new file mode 100644 index 000000000000..1b1d743dff66 --- /dev/null +++ b/sys/net/gnrc/netif/init_devs/auto_init_sam0_eth.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_auto_init_gnrc_netif + * @{ + * + * @brief Auto initialize sam0 ethernet driver + * + * @author Dylan Laduranty + */ + +#ifdef MODULE_SAM0_ETH + +#include "net/gnrc/netif/ethernet.h" +#include "sam0_eth_netdev.h" + +static netdev_t sam0eth; +static char stack[THREAD_STACKSIZE_DEFAULT]; +static gnrc_netif_t _netif; + +extern void sam0_eth_setup(netdev_t *netdev); + +void auto_init_sam0_eth(void) +{ + /* setup netdev device */ + sam0_eth_setup(&sam0eth); + /* initialize netdev <-> gnrc adapter state */ + gnrc_netif_ethernet_create(&_netif, stack, THREAD_STACKSIZE_DEFAULT, + GNRC_NETIF_PRIO, "sam0_eth", &sam0eth); +} + +#else +typedef int dont_be_pedantic; +#endif /* MODULE_SAM0_ETH */ +/** @} */ diff --git a/sys/net/gnrc/netif/init_devs/init.c b/sys/net/gnrc/netif/init_devs/init.c index b193d5eadd68..beb590cd07a7 100644 --- a/sys/net/gnrc/netif/init_devs/init.c +++ b/sys/net/gnrc/netif/init_devs/init.c @@ -99,6 +99,11 @@ void gnrc_netif_init_devs(void) auto_init_dose(); } + if (IS_USED(MODULE_SAM0_ETH)) { + extern void auto_init_sam0_eth(void); + auto_init_sam0_eth(); + } + if (IS_USED(MODULE_SLIPDEV)) { extern void auto_init_slipdev(void); auto_init_slipdev();