This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push: new c5a3089e87 drivers/net: Add support for the NCV7410 10BASE-T1S MAC-PHY c5a3089e87 is described below commit c5a3089e87792228be37ac03cd195fc91cb90fd6 Author: michal matias <mich4l.mat...@gmail.com> AuthorDate: Wed Jun 25 02:21:00 2025 +0200 drivers/net: Add support for the NCV7410 10BASE-T1S MAC-PHY This commit adds driver for the Onsemi NCV7410 10BASE-T1S Ethernet MAC-PHY. Signed-off-by: michal matias <mich4l.mat...@gmail.com> --- drivers/net/CMakeLists.txt | 4 + drivers/net/Kconfig | 24 + drivers/net/Make.defs | 4 + drivers/net/ncv7410.c | 1662 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/ncv7410.h | 291 ++++++++ include/nuttx/net/ncv7410.h | 88 +++ 6 files changed, 2073 insertions(+) diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt index 86c96da39d..3d0937f7f5 100644 --- a/drivers/net/CMakeLists.txt +++ b/drivers/net/CMakeLists.txt @@ -49,6 +49,10 @@ if(CONFIG_NET) list(APPEND SRCS enc28j60.c) endif() + if(CONFIG_NCV7410) + list(APPEND SRCS ncv7410.c) + endif() + if(CONFIG_ENCX24J600) list(APPEND SRCS encx24j600.c) endif() diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dee800c9db..5b7c1841c8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -287,6 +287,30 @@ config ENC28J60_REGDEBUG endif # ENC28J60 +menuconfig NCV7410 + bool "onsemi NCV7410 support" + default n + select SPI + select ARCH_HAVE_NETDEV_STATISTICS + ---help--- + Enable support for onsemi NCV7410 10BASE-T1S MAC-PHY + +if NCV7410 + +config NCV7410_INT_PIN + int "NCV7410 interrupt pin" + default 3 + ---help--- + Number of boarad pin to be connected to NCV7410's interrupt signal + +config NCV7410_FREQUENCY + int "SPI frequency" + default 20000000 + ---help--- + NCV7410 SPI bus frequency + +endif # NCV7410 + menuconfig ENCX24J600 bool "Microchip ENCX24J600 support" default n diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs index 20a2b2b138..f341749752 100644 --- a/drivers/net/Make.defs +++ b/drivers/net/Make.defs @@ -50,6 +50,10 @@ ifeq ($(CONFIG_ENC28J60),y) CSRCS += enc28j60.c endif +ifeq ($(CONFIG_NCV7410),y) + CSRCS += ncv7410.c +endif + ifeq ($(CONFIG_ENCX24J600),y) CSRCS += encx24j600.c endif diff --git a/drivers/net/ncv7410.c b/drivers/net/ncv7410.c new file mode 100644 index 0000000000..d21647c885 --- /dev/null +++ b/drivers/net/ncv7410.c @@ -0,0 +1,1662 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + struct netdev_lowerhalf_s dev; /* Driver data visible by the net stack + * (must be placed first) */ + mutex_t lock; /* Lock for data race prevention */ + FAR struct spi_dev_s *spi; /* The SPI device instance */ + int irqnum; /* irq number of the interrupt pin */ + struct ncv7410_config_s *config; /* NCV7410 configuration */ + uint8_t ifstate; /* Driver state from ncv_ifstate_e enum */ + + struct work_s interrupt_work; /* wq handle for the interrupt work */ + struct work_s io_work; /* wq handle for the io work */ + + int txc; /* TX credits */ + int rca; /* RX chunks available */ + + FAR netpkt_t *tx_pkt; /* Pointer to the TX netpacket */ + FAR netpkt_t *rx_pkt; /* Pointer to the RX netpacket */ + int tx_pkt_idx; /* Position in the TX netpacket */ + int rx_pkt_idx; /* Position in the RX netpacket */ + int tx_pkt_len; /* Length of the TX packet */ + bool rx_pkt_ready; /* RX packet ready to be received flag */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Bit calculations */ + +static int ncv_get_parity(uint32_t word); +static uint8_t ncv_bitrev8(uint8_t byte); + +/* SPI transfers */ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word); + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word); + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits); + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer); + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer); + +/* Interrupt handling */ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg); +static void ncv_interrupt_work(FAR void *arg); + +/* Data Transaction Protocol logic */ + +static void ncv_io_work(FAR void *arg); +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf); +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv); +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf); +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv); + +/* SPI inline utility functions */ + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv); + +/* ncv7410 reset and configuration */ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv); +static int ncv_config(FAR struct ncv7410_driver_s *priv); +static int ncv_enable(FAR struct ncv7410_driver_s *priv); +static int ncv_disable(FAR struct ncv7410_driver_s *priv); +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv); + +/* Driver buffer manipulation */ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv); + +/* NuttX callback functions */ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev); + +/* Debug */ + +#ifdef CONFIG_DEBUG_NET_INFO +static void ncv_print_footer(uint32_t footer); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct netdev_ops_s g_ncv7410_ops = +{ + .ifup = ncv7410_ifup, + .ifdown = ncv7410_ifdown, + .transmit = ncv7410_transmit, + .receive = ncv7410_receive, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv_interrupt + * + * Description: + * Schedule interrupt work when the interrupt signal from MAC-PHY is + * received. + * + * Input Parameters: + * irq - not used + * context - not used + * arg - ncv7410_driver_s priv structure to be passed to the interrupt + * worker + * + * Returned Value: + * OK is always returned. + * + ****************************************************************************/ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)arg; + + ninfo("NCV7410 interrupt!\n"); + + /* schedule interrupt work */ + + work_queue(NCVWORK, &priv->interrupt_work, ncv_interrupt_work, priv, 0); + return OK; +} + +/**************************************************************************** + * Name: ncv_interrupt_work + * + * Description: + * Identify the interrupt source and perform necessary work. + * + * Input Parameters: + * arg - pointer to driver private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_interrupt_work(FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)arg; + uint32_t footer; + + nxmutex_lock(&priv->lock); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->lock); + return; + } + + ninfo("NCV7410 interrupt worker invoked!\n"); + + /* poll the data chunk footer */ + + if (ncv_poll_footer(priv, &footer)) + { + nerr("Polling footer unsuccessful\n"); + + /* TODO: don't */ + + PANIC(); + } + +#ifdef CONFIG_DEBUG_NET_INFO + ncv_print_footer(footer); +#endif + + /* if EXST in the footer, check enabled sources + * STATUS0, link-status in clause 22 phy registers + * (not yet implemented) + */ + + /* update MAC-PHY buffer status */ + + priv->txc = oa_tx_credits(footer); + priv->rca = oa_rx_available(footer); + + if ((priv->tx_pkt && priv->txc) || priv->rca) + { + /* schedule IO work */ + + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + } + + nxmutex_unlock(&priv->lock); +} + +/**************************************************************************** + * Name: ncv_io_work + * + * Description: + * Exchange data chunk with the MAC-PHY. + * + * Input Parameters: + * arg - pointer to driver private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_io_work(FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)arg; + + uint8_t txbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + uint8_t rxbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + + uint32_t header; + uint32_t footer; + + nxmutex_lock(&priv->lock); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->lock); + return; + } + + header = ncv_prepare_chunk_exchange(priv, txbuf); + + /* Perform the SPI exchange */ + + if (ncv_exchange_chunk(priv, txbuf, rxbuf, header, &footer)) + { + nerr("Error during chunk exchange\n"); + + /* TODO: do not panic, the best is probably to report the error + * and reset MAC to some defined state and reset driver + */ + + PANIC(); + } + + ncv_try_finish_tx_packet(priv); + + ncv_handle_rx_chunk(priv, footer, rxbuf); + + /* schedule further work if needed */ + + if ((priv->tx_pkt && priv->txc) || priv->rca) + { + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + } + + nxmutex_unlock(&priv->lock); +} + +/**************************************************************************** + * Name: ncv_prepare_chunk_exchange + * + * Description: + * Determine whether there is data to transmit or receive. + * Set the appropriate header bitfields and fill the txbuf accordingly. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * txbuf - pointer to the transmit chunk buffer + * + * Returned Value: + * Returns the prepared chunk header. + * + ****************************************************************************/ + +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf) +{ + uint32_t header = 0; + int txlen; + + if (priv->tx_pkt && priv->txc) + { + header |= (1 << OA_DV_POS); /* Data Valid */ + + if (priv->tx_pkt_idx == 0) + { + header |= (1 << OA_SV_POS) /* Start Valid */ + | (0 << OA_SWO_POS); /* Start Word Offset = 0 */ + } + + txlen = priv->tx_pkt_len - priv->tx_pkt_idx; + + if (txlen <= NCV_CHUNK_DEFAULT_PAYLOAD_SIZE) + { + header |= (1 << OA_EV_POS) /* End Valid */ + | ((txlen - 1) << OA_EBO_POS); /* End Byte Offset */ + } + else + { + txlen = NCV_CHUNK_DEFAULT_PAYLOAD_SIZE; + } + + /* copy data from network to txbuf */ + + netpkt_copyout(&priv->dev, txbuf, priv->tx_pkt, + txlen, priv->tx_pkt_idx); + priv->tx_pkt_idx += txlen; + } + + if (ncv_can_rx(priv) == false) + { + header |= (1 << OA_NORX_POS); /* no rx */ + } + + return header; +} + +/**************************************************************************** + * Name: ncv_can_rx + * + * Description: + * Determine whether rx data is available and whether it can be received. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * If it is possible to receive an rx chunk, true is returned, + * otherwise false is returned. + * + ****************************************************************************/ + +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv) +{ + if (!priv->rca) + { + return false; + } + + if (priv->rx_pkt_ready) + { + return false; + } + + if (priv->rx_pkt) + { + return true; + } + + /* no RX packet, try to alloc */ + + priv->rx_pkt = netpkt_alloc(&priv->dev, NETPKT_RX); + if (priv->rx_pkt) + { + return true; + } + + ninfo("INFO: Failed to alloc rx netpkt\n"); + + /* there is no buffer for rx data */ + + return false; +} + +/**************************************************************************** + * Name: ncv_try_finish_tx_packet + * + * Description: + * Check whether the entire packet has been transmitted. + * If so, free the tx netpkt and notify the upperhalf. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv) +{ + if (priv->tx_pkt && (priv->tx_pkt_idx == priv->tx_pkt_len)) + { + ncv_release_tx_packet(priv); + netdev_lower_txdone(&priv->dev); + } +} + +/**************************************************************************** + * Name: ncv_handle_rx_chunk + * + * Description: + * Parse the received footer, update buffer status and handle data + * in the rxbuf. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * footer - the received footer + * rxbuf - pointer to the received data buffer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf) +{ + int rxlen; + int newlen; + + /* update buffer status */ + + priv->txc = oa_tx_credits(footer); + priv->rca = oa_rx_available(footer); + + /* check rx_pkt && !rx_pkt_ready, + * oa_data_valid flag might have been set due to an SPI error + */ + + if (oa_data_valid(footer) && priv->rx_pkt && !priv->rx_pkt_ready) + { + if (oa_start_valid(footer)) + { + priv->rx_pkt_idx = 0; + } + + if (oa_end_valid(footer)) + { + if (oa_frame_drop(footer)) + { + ncv_release_rx_packet(priv); + return; + } + + rxlen = oa_end_byte_offset(footer) + 1; + } + else + { + rxlen = NCV_CHUNK_DEFAULT_PAYLOAD_SIZE; + } + + newlen = priv->rx_pkt_idx + rxlen; + + if (newlen > NCV_MAX_FRAME_SIZE(priv)) + { + nwarn("Dropping chunk of a packet that is too long"); + + /* set index so that a subsequent chunk with + * smaller payload won't pass + */ + + priv->rx_pkt_idx = NCV_MAX_FRAME_SIZE(priv) + 1; + return; + } + + netpkt_copyin(&priv->dev, priv->rx_pkt, rxbuf, + rxlen, priv->rx_pkt_idx); + priv->rx_pkt_idx = newlen; + + if (oa_end_valid(footer)) + { + /* finalize packet and notify the upper */ + + ncv_finalize_rx_packet(priv); + netdev_lower_rxready(&priv->dev); + } + } +} + +/**************************************************************************** + * Name: ncv_finalize_rx_packet + * + * Description: + * Strip down last 4 bytes (FCS) from the rx packet and mark it ready. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_setdatalen(&priv->dev, priv->rx_pkt, + netpkt_getdatalen(&priv->dev, priv->rx_pkt) - 4); + priv->rx_pkt_ready = true; +} + +/**************************************************************************** + * Name: ncv_release_tx_packet + * + * Description: + * Release the tx packet. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_free(&priv->dev, priv->tx_pkt, NETPKT_TX); + priv->tx_pkt = NULL; +} + +/**************************************************************************** + * Name: ncv_release_rx_packet + * + * Description: + * Release the rx packet. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_free(&priv->dev, priv->rx_pkt, NETPKT_RX); + priv->rx_pkt = NULL; +} + +/**************************************************************************** + * Name: ncv_get_parity + * + * Description: + * Obtain parity of a 32-bit word. + * + * Input Parameters: + * word - 32-bit word, subject to the parity calculation + * + * Returned Value: + * If the parity of the word is even, zero is returned. + * Otherwise one is returned. + * + ****************************************************************************/ + +static int ncv_get_parity(uint32_t word) +{ + /* www-graphics.stanford.edu/~seander/bithacks.html */ + + word ^= word >> 1; + word ^= word >> 2; + word = (word & 0x11111111u) * 0x11111111u; + return (word >> 28) & 1; +} + +/**************************************************************************** + * Name: ncv_bitrev8 + * + * Description: + * Perform a bit reverse of a byte. + * + * Input Parameters: + * b - byte to be reversed + * + * Returned Value: + * Byte with reversed bits is returned. + * + ****************************************************************************/ + +static uint8_t ncv_bitrev8(uint8_t byte) +{ + /* https://stackoverflow.com/a/2602885 */ + + byte = (byte & 0xf0) >> 4 | (byte & 0x0f) << 4; + byte = (byte & 0xcc) >> 2 | (byte & 0x33) << 2; + byte = (byte & 0xaa) >> 1 | (byte & 0x55) << 1; + return byte; +} + +/**************************************************************************** + * Name: ncv_(select/deselect)_spi + * + * Description: + * Helper functions to setup SPI hardware. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv) +{ + SPI_LOCK(priv->spi, true); + + SPI_SETMODE(priv->spi, OA_SPI_MODE); + SPI_SETBITS(priv->spi, OA_SPI_NBITS); + SPI_HWFEATURES(priv->spi, 0); /* disable HW features */ + SPI_SETFREQUENCY(priv->spi, CONFIG_NCV7410_FREQUENCY); + + SPI_SELECT(priv->spi, priv->config->id, true); +} + +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv) +{ + SPI_SELECT(priv->spi, priv->config->id, false); + + SPI_LOCK(priv->spi, false); +} + +/**************************************************************************** + * Name: ncv_write_reg + * + * Description: + * Write to a MAC-PHY register. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * regid - Register id encapsulating MMS and ADDR + * word - 32-bit word to be written to the register + * + * Returned Value: + * On a successful transaction OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word) +{ + uint32_t txdata[3]; + uint32_t rxdata[3]; + uint8_t mms = OA_REGID_GET_MMS(regid); + uint16_t addr = OA_REGID_GET_ADDR(regid); + + /* prepare header */ + + uint32_t header = (1 << OA_WNR_POS) /* Write Not Read */ + | (mms << OA_MMS_POS) + | (addr << OA_ADDR_POS); + int parity = ncv_get_parity(header); + header |= parity ? 0 : OA_P_MASK; /* make header odd parity */ + + /* convert to big endian */ + + header = htobe32(header); + word = htobe32(word); + + /* prepare exchange */ + + txdata[0] = header; + txdata[1] = word; + + ncv_select_spi(priv); + SPI_EXCHANGE(priv->spi, txdata, rxdata, 12); + ncv_deselect_spi(priv); + if (rxdata[1] != header) + { + nerr("Error writing register\n"); + return ERROR; + } + + ninfo("Writing register OK\n"); + return OK; +} + +/**************************************************************************** + * Name: ncv_read_reg + * + * Description: + * Read a MAC-PHY register. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * regid - register id encapsulating MMS and ADDR + * word - pointer to a 32-bit destination variable + * + * Returned Value: + * On successful transaction OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word) +{ + uint32_t txdata[3]; + uint32_t rxdata[3]; + uint8_t mms = OA_REGID_GET_MMS(regid); + uint16_t addr = OA_REGID_GET_ADDR(regid); + int parity; + uint32_t header; + + /* prepare header */ + + header = (mms << OA_MMS_POS) + | (addr << OA_ADDR_POS); + parity = ncv_get_parity(header); + header |= parity ? 0 : OA_P_MASK; /* make header odd parity */ + + /* convert to big endian */ + + header = htobe32(header); + + /* prepare exchange */ + + txdata[0] = header; + + ncv_select_spi(priv); + SPI_EXCHANGE(priv->spi, txdata, rxdata, 12); + ncv_deselect_spi(priv); + + *word = be32toh(rxdata[2]); + if (rxdata[1] != header) + { + nerr("Error reading register\n"); + return ERROR; + } + + ninfo("Reading register OK\n"); + return OK; +} + +/**************************************************************************** + * Name: ncv_set_clear_bits + * + * Description: + * Perform a read-modify-write operation on a given register + * while setting bits from the setbits argument and clearing bits from + * the clearbits argument. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * regid - register id of the register to be modified + * setbits - bits set to one will be set in the register + * clearbits - bits set to one will be cleared in the register + * + * Returned Value: + * On a successful transaction OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits) +{ + uint32_t regval; + + if (ncv_read_reg(priv, regid, ®val)) + { + return ERROR; + } + + regval |= setbits; + regval &= ~clearbits; + + if (ncv_write_reg(priv, regid, regval)) + { + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_exchange_chunk + * + * Description: + * Send a data chunk to MAC-PHY and simultaneously receive chunk. + * + * Computing header parity, checking footer parity, converting to proper + * endianness and setting DNC flag is done by this function. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * txbuf - buffer with transmit chunk data + * rxbuf - buffer to save the received chunk to + * header - header controlling the transaction + * footer - pointer to a 32-bit value for the footer + * + * Returned Value: + * On a successful transaction OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer) +{ + header |= (1 << OA_DNC_POS); + header |= (!ncv_get_parity(header) << OA_P_POS); + header = htobe32(header); + + ncv_select_spi(priv); + + /* this depends on SW Chip Select */ + + SPI_EXCHANGE(priv->spi, (uint8_t *) &header, rxbuf, 4); + SPI_EXCHANGE(priv->spi, txbuf, + &rxbuf[4], NCV_CHUNK_DEFAULT_PAYLOAD_SIZE - 4); + SPI_EXCHANGE(priv->spi, &txbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE - 4], + (uint8_t *)footer, 4); + ncv_deselect_spi(priv); + + *footer = be32toh(*footer); + if (!ncv_get_parity(*footer)) + { + nerr("Wrong parity in the footer\n"); + return ERROR; + } + + if (oa_header_bad(*footer)) + { + nerr("HDRB set in the footer\n"); + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_poll_footer + * + * Description: + * Poll a data transaction chunk footer. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * footer - pointer to a 32-bit footer destination variable + * + * Returned Value: + * On a successful transaction OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer) +{ + uint8_t txdata[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + uint8_t rxdata[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + uint32_t header; + + header = (1 << OA_DNC_POS) /* Data Not Control */ + | (1 << OA_NORX_POS); /* No Read */ + + if (ncv_exchange_chunk(priv, txdata, rxdata, header, footer)) + { + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_reset + * + * Description: + * Perform SW reset of the MAC-PHY. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * On a successful reset OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv) +{ + int tries = NCV_RESET_TRIES; + uint32_t regval = (1 << OA_RESET_SWRESET_POS); + + if (ncv_write_reg(priv, OA_RESET_REGID, regval)) + { + return ERROR; + } + + /* check whether the RESET bit cleared itself */ + + do + { + if (ncv_read_reg(priv, OA_RESET_REGID, ®val)) + { + return ERROR; + } + } + while (tries-- && (regval & OA_RESET_SWRESET_MASK)); + + if (regval & OA_RESET_SWRESET_MASK) + { + return ERROR; + } + + /* check whether the reset complete flag is set */ + + tries = NCV_RESET_TRIES; + + do + { + if (ncv_read_reg(priv, OA_STATUS0_REGID, ®val)) + { + return ERROR; + } + } + while (tries-- && !(regval & OA_STATUS0_RESETC_MASK)); + + if (!(regval & OA_STATUS0_RESETC_MASK)) + { + return ERROR; + } + + /* clear HDRE in STATUS0 (due to a bug in NCV7410) */ + + if (ncv_write_reg(priv, OA_STATUS0_REGID, (1 << OA_STATUS0_HDRE_POS))) + { + return ERROR; + } + + /* clear reset complete flag */ + + if (ncv_write_reg(priv, OA_STATUS0_REGID, (1 << OA_STATUS0_RESETC_POS))) + { + return ERROR; + } + + /* blink with LEDs for debugging purposes */ + + for (int i = 0; i < 4; i++) + { + regval = 0x0302; + if (ncv_write_reg(priv, NCV_DIO_CONFIG_REGID, regval)) + { + return ERROR; + } + + nxsig_usleep(250000); + regval = 0x0203; + if (ncv_write_reg(priv, NCV_DIO_CONFIG_REGID, regval)) + { + return ERROR; + } + + nxsig_usleep(250000); + } + + /* set DIOs to default */ + + regval = NCV_DIO_CONFIG_DEF; + if (ncv_write_reg(priv, NCV_DIO_CONFIG_REGID, regval)) + { + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_config + * + * Description: + * Configure the MAC-PHY into promiscuous mode and set the SYNC flag. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * On success OK is returned, otherwise ERROR is returned. + * + * Assumptions: + * The function is called after the MAC address is initialized. + * + ****************************************************************************/ + +static int ncv_config(FAR struct ncv7410_driver_s *priv) +{ + uint32_t regval; +#ifndef CONFIG_NET_PROMISCUOUS + uint8_t *mac = priv->dev.netdev.d_mac.ether.ether_addr_octet; +#endif + + ninfo("Configuring NCV7410\n"); + + /* setup LEDs DIO0: txrx blink + * DIO1: link enabled and link status up + */ + + regval = (NCV_DIO_TXRX_FUNC << NCV_DIO0_FUNC_POS) + | (NCV_DIO_LINK_CTRL_FUNC << NCV_DIO1_FUNC_POS) + | (1 << NCV_DIO0_OUT_VAL_POS) + | (1 << NCV_DIO1_OUT_VAL_POS); + + if (ncv_write_reg(priv, NCV_DIO_CONFIG_REGID, regval)) + { + return ERROR; + } + + /* enable MAC TX, RX, enable transmit FCS computation on MAC, + * enable MAC address filtering + */ + + regval = (1 << NCV_MAC_CONTROL0_FCSA_POS) + | (1 << NCV_MAC_CONTROL0_TXEN_POS) + | (1 << NCV_MAC_CONTROL0_RXEN_POS) + | (1 << NCV_MAC_CONTROL0_ADRF_POS); + +#ifdef CONFIG_NET_PROMISCUOUS + /* disable MAC address filtering */ + + regval &= ~(1 << NCV_MAC_CONTROL0_ADRF_POS); +#endif + + if (ncv_write_reg(priv, NCV_MAC_CONTROL0_REGID, regval)) + { + return ERROR; + } + +#ifndef CONFIG_NET_PROMISCUOUS + /* setup MAC address filter */ + + regval = (mac[2] << 24) + | (mac[3] << 16) + | (mac[4] << 8) + | (mac[5]); + + if (ncv_write_reg(priv, NCV_ADDRFILT0L_REGID, regval)) + { + return ERROR; + } + + regval = (1 << 31) /* enable filter */ + | (mac[0] << 8) + | (mac[1]); + + if (ncv_write_reg(priv, NCV_ADDRFILT0H_REGID, regval)) + { + return ERROR; + } + + regval = 0xffffffff; + + if (ncv_write_reg(priv, NCV_ADDRMASK0L_REGID, regval)) + { + return ERROR; + } + + regval = 0x0000ffff; + + if (ncv_write_reg(priv, NCV_ADDRMASK0H_REGID, regval)) + { + return ERROR; + } + +#endif + + /* enable rx buffer overflow interrupt */ + + regval = OA_IMSK0_DEF & ~(1 << OA_IMSK0_RXBOEM_POS); + + if (ncv_write_reg(priv, OA_IMSK0_REGID, regval)) + { + return ERROR; + } + + /* setup SPI protocol and set SYNC flag */ + + regval = (1 << OA_CONFIG0_SYNC_POS) + | (1 << OA_CONFIG0_CSARFE_POS) + | (1 << OA_CONFIG0_ZARFE_POS) + | (1 << OA_CONFIG0_RXCTE_POS) /* a bit lower latency */ + | (3 << OA_CONFIG0_TXCTHRESH_POS) + | (6 << OA_CONFIG0_CPS_POS); + + if (ncv_write_reg(priv, OA_CONFIG0_REGID, regval)) + { + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_enable + * + * Description: + * Enable TX and RX on the MAC-PHY. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * On success OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_enable(FAR struct ncv7410_driver_s *priv) +{ + /* enable PHY */ + + uint32_t setbits; + + ninfo("Enabling NCV7410\n"); + + /* enable RX and TX in PHY */ + + setbits = (1 << OA_PHY_CONTROL_LCTL_POS); + + if (ncv_set_clear_bits(priv, OA_PHY_CONTROL_REGID, setbits, 0)) + { + return ERROR; + } + + /* enable PHY interrupt */ + + setbits = (1 << OA_IMSK0_PHYINTM_POS); + + if (ncv_set_clear_bits(priv, OA_IMSK0_REGID, setbits, 0)) + { + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_disable + * + * Description: + * Disable TX and RX on the MAC-PHY. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * On success OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_disable(FAR struct ncv7410_driver_s *priv) +{ + /* disable PHY */ + + uint32_t clearbits; + + ninfo("Disabling NCV7410\n"); + + /* disable PHY interrupt */ + + clearbits = (1 << OA_IMSK0_PHYINTM_POS); + + if (ncv_set_clear_bits(priv, OA_IMSK0_REGID, 0, clearbits)) + { + return ERROR; + } + + /* disable RX and TX in PHY */ + + clearbits = (1 << OA_PHY_CONTROL_LCTL_POS); + + if (ncv_set_clear_bits(priv, OA_PHY_CONTROL_REGID, 0, clearbits)) + { + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: ncv_init_mac_addr + * + * Description: + * Read the MAC-PHY's factory-assigned MAC address and copy it into + * the network device state structure. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * On success OK is returned, otherwise ERROR is returned. + * + ****************************************************************************/ + +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv) +{ + uint32_t regval; + uint8_t mac[6]; + + if (ncv_read_reg(priv, OA_PHYID_REGID, ®val)) + { + return ERROR; + } + + mac[0] = ncv_bitrev8(regval >> 26); + mac[1] = ncv_bitrev8(regval >> 18); + mac[2] = ncv_bitrev8(regval >> 10); + + if (ncv_read_reg(priv, NCV_MACID1_REGID, ®val)) + { + return ERROR; + } + + mac[3] = regval; + + if (ncv_read_reg(priv, NCV_MACID0_REGID, ®val)) + { + return ERROR; + } + + mac[4] = regval >> 8; + mac[5] = regval; + + memcpy(&priv->dev.netdev.d_mac.ether, &mac, sizeof(struct ether_addr)); + + return OK; +} + +/**************************************************************************** + * Name: ncv_reset_driver_buffers + * + * Description: + * If allocated, release both tx and rx netpackets and reset buffer status + * to the default. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv) +{ + priv->txc = 0; + priv->rca = 0; + + if (priv->tx_pkt) + { + ncv_release_tx_packet(priv); + } + + if (priv->rx_pkt) + { + ncv_release_rx_packet(priv); + } + + priv->tx_pkt_idx = 0; + priv->rx_pkt_idx = 0; + priv->tx_pkt_len = 0; + priv->rx_pkt_ready = false; +} + +/**************************************************************************** + * Name: ncv_print_footer + * + * Description: + * print individual bitfield of a receive chunk footer + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_NET_INFO +static void ncv_print_footer(uint32_t footer) +{ + ninfo("Footer:\n"); + ninfo(" EXST: %d\n", oa_ext_status(footer)); + ninfo(" HDRB: %d\n", oa_header_bad(footer)); + ninfo(" SYNC: %d\n", oa_mac_phy_sync(footer)); + ninfo(" RCA: %d\n", oa_rx_available(footer)); + ninfo(" DV: %d\n", oa_data_valid(footer)); + ninfo(" SV: %d\n", oa_start_valid(footer)); + ninfo(" SWO: %d\n", oa_start_word_offset(footer)); + ninfo(" FD: %d\n", oa_frame_drop(footer)); + ninfo(" EV: %d\n", oa_end_valid(footer)); + ninfo(" EBO: %d\n", oa_end_byte_offset(footer)); + ninfo(" RTSA: %d\n", oa_rx_frame_timestamp_added(footer)); + ninfo(" RTSP: %d\n", oa_rx_frame_timestamp_parity(footer)); + ninfo(" TXC: %d\n", oa_tx_credits(footer)); +} +#endif + +/**************************************************************************** + * Netdev upperhalf callbacks + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv7410_ifup + * + * Description: + * NuttX callback: Bring up the Ethernet interface + * + * Input Parameters: + * dev - reference to the NuttX driver state structure + * + * Returned Values: + * On success OK is returned, otherwise negated errno is returned. + * + ****************************************************************************/ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)dev; + + if (priv->ifstate == NCV_INIT_UP) + { + nerr("Tried to bring NCV7410 interface up when already up\n"); + return -EINVAL; + } + + ninfo("Bringing up NCV7410\n"); + + if (priv->ifstate == NCV_RESET) + { + if (ncv_config(priv) == ERROR) + { + nerr("Error configuring NCV7410\n"); + return -EIO; + } + + priv->ifstate = NCV_INIT_DOWN; + } + + /* set NCV_INIT_UP prior to enabling to allow ncv_interrupt_work right + * after MAC-PHY enable + */ + + priv->ifstate = NCV_INIT_UP; + + if (ncv_enable(priv) == ERROR) + { + nerr("Error enabling NCV7410\n"); + priv->ifstate = NCV_INIT_DOWN; + return -EIO; + } + + /* schedule interrupt work to initialize txc and rca */ + + work_queue(NCVWORK, &priv->interrupt_work, ncv_interrupt_work, priv, 0); + + return OK; +} + +/**************************************************************************** + * Name: ncv7410_ifdown + * + * Description: + * NuttX callback: Shut down the Ethernet interface. + * + * Input Parameters: + * dev - reference to the NuttX driver state structure + * + * Returned Values: + * On success OK is returned, otherwise negated errno is returned. + * + ****************************************************************************/ + +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)dev; + + nxmutex_lock(&priv->lock); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->lock); + nerr("Tried to bring the NCV7410 interface down but it is not up\n"); + return -EINVAL; + } + + work_cancel(NCVWORK, &priv->interrupt_work); + work_cancel(NCVWORK, &priv->io_work); + + if (ncv_disable(priv) == ERROR) + { + nxmutex_unlock(&priv->lock); + nerr("Error disabling NCV7410\n"); + return -EIO; + } + + ncv_reset_driver_buffers(priv); + + priv->ifstate = NCV_INIT_DOWN; + + nxmutex_unlock(&priv->lock); + + return OK; +} + +/**************************************************************************** + * Name: ncv7410_transmit + * + * Description: + * NuttX callback: Transmit the given packet. + * + * Input Parameters: + * dev - reference to the NuttX driver state structure + * pkt - network packet to be transmitted + * + * Returned Values: + * On success OK is returned, otherwise negated errno is returned. + * + ****************************************************************************/ + +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)dev; + + nxmutex_lock(&priv->lock); + + if (priv->tx_pkt || priv->ifstate != NCV_INIT_UP) + { + /* previous tx packet was not yet sent to the network + * or the interface was shut down while waiting for the lock + */ + + nxmutex_unlock(&priv->lock); + return -EAGAIN; + } + + priv->tx_pkt_idx = 0; + priv->tx_pkt_len = netpkt_getdatalen(dev, pkt); + priv->tx_pkt = pkt; + + nxmutex_unlock(&priv->lock); + + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + return OK; +} + +/**************************************************************************** + * Name: ncv7410_receive + * + * Description: + * NuttX callback: Claims an rx packet if available. + * + * Input Parameters: + * dev - reference to the NuttX driver state structure + * + * Returned Values: + * If the rx packet is ready, its pointer is returned. + * NULL is returned otherwise. + * + ****************************************************************************/ + +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)dev; + + nxmutex_lock(&priv->lock); + + if (priv->rx_pkt_ready) + { + netpkt_t *retval = priv->rx_pkt; + priv->rx_pkt_ready = false; + priv->rx_pkt = NULL; + nxmutex_unlock(&priv->lock); + return retval; + } + + nxmutex_unlock(&priv->lock); + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv7410_initialize + * + * Description: + * Initialize the Ethernet driver. + * + * Input Parameters: + * spi - reference to the SPI driver state data + * irq - irq number of the pin connected to MAC-PHY's interrupt signal + * + * Returned Value: + * On success OK is returned, otherwise negated errno is returned. + * + ****************************************************************************/ + +int ncv7410_initialize(FAR struct spi_dev_s *spi, int irq, + struct ncv7410_config_s *config) +{ + FAR struct ncv7410_driver_s *priv = NULL; + FAR struct netdev_lowerhalf_s *netdev = NULL; + int retval; + + /* Allocate the interface structure */ + + priv = kmm_zalloc(sizeof(*priv)); + if (priv == NULL) + { + nerr("Could not allocate data for ncv7410 priv\n"); + return -ENOMEM; + } + + priv->spi = spi; /* Save the SPI instance */ + priv->irqnum = irq; /* Save the Interrupt Request Number */ + priv->config = config; /* Save the reference to the configuration */ + + /* Reset NCV7410 chip */ + + if (ncv_reset(priv)) + { + nerr("Error resetting NCV7410\n"); + retval = -EIO; + goto errout; + } + + priv->ifstate = NCV_RESET; + ninfo("Resetting NCV7410 OK\n"); + + if (ncv_init_mac_addr(priv)) + { + nerr("Error initializing NCV7410 MAC address\n"); + retval = -EIO; + goto errout; + } + + ninfo("Initializing MAC address OK\n"); + + /* Attach ISR */ + + irq_attach(priv->irqnum, ncv_interrupt, priv); + + /* Init lock */ + + nxmutex_init(&priv->lock); + + /* Register the device with the OS */ + + netdev = &priv->dev; + netdev->quota[NETPKT_TX] = NCV7410_TX_QUOTA; + netdev->quota[NETPKT_RX] = NCV7410_RX_QUOTA; + netdev->ops = &g_ncv7410_ops; + + retval = netdev_lower_register(netdev, NET_LL_ETHERNET); + if (retval == OK) + { + ninfo("Successfully registered NCV7410 network driver\n"); + return OK; + } + + nerr("Error registering NCV7410 network driver: %d\n", retval); + +errout: + kmm_free(priv); + return retval; +} diff --git a/drivers/net/ncv7410.h b/drivers/net/ncv7410.h new file mode 100644 index 0000000000..3638f751f3 --- /dev/null +++ b/drivers/net/ncv7410.h @@ -0,0 +1,291 @@ +/**************************************************************************** + * drivers/net/ncv7410.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +#ifndef __DRIVERS_NET_NCV7410_H +#define __DRIVERS_NET_NCV7410_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/bits.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* NuttX SPI mode number for SPI config as defined in OpenAlliance TC6 */ + +#define OA_SPI_MODE 0 + +/* Number of bits in a SPI word */ + +#define OA_SPI_NBITS 8 + +#define NCV_CHUNK_DEFAULT_PAYLOAD_SIZE 64 +#define NCV_CHUNK_DEFAULT_SIZE (NCV_CHUNK_DEFAULT_PAYLOAD_SIZE + 4) + +typedef uint32_t oa_regid_t; + +#define OA_MAKE_REGID(mms, addr) \ + (((uint32_t)(mms) << 16) | ((uint32_t)(addr) & 0xFFFF)) + +#define OA_REGID_GET_MMS(regid) ((uint8_t)((regid >> 16) & 0xF)) +#define OA_REGID_GET_ADDR(regid) ((uint16_t)(regid & 0xFFFF)) + +#define OA_IDVER_MMS 0 +#define OA_IDVER_ADDR 0x0U +#define OA_IDVER_REGID OA_MAKE_REGID(OA_IDVER_MMS, OA_IDVER_ADDR) + +#define OA_PHYID_MMS 0 +#define OA_PHYID_ADDR 0x1U +#define OA_PHYID_REGID OA_MAKE_REGID(OA_PHYID_MMS, OA_PHYID_ADDR) +#define OA_PHYID_OUI_MASK GENMASK(31, 10) +#define OA_PHYID_OUI_POS 10 +#define OA_PHYID_MODEL_MASK GENMASK(9, 4) +#define OA_PHYID_MODEL_POS 4 +#define OA_PHYID_REV_MASK GENMASK(3, 0) +#define OA_PHYID_REV_POS 0 + +#define OA_STDCAP_MMS 0 +#define OA_STDCAP_ADDR 0x2U +#define OA_STDCAP_REGID OA_MAKE_REGID(OA_STDCAP_MMS, OA_STDCAP_ADDR) + +#define OA_RESET_MMS 0 +#define OA_RESET_ADDR 0x3U +#define OA_RESET_REGID OA_MAKE_REGID(OA_RESET_MMS, OA_RESET_ADDR) +#define OA_RESET_SWRESET_MASK BIT(0) +#define OA_RESET_SWRESET_POS 0 + +#define OA_CONFIG0_MMS 0 +#define OA_CONFIG0_ADDR 0x4U +#define OA_CONFIG0_REGID OA_MAKE_REGID(OA_CONFIG0_MMS, OA_CONFIG0_ADDR) +#define OA_CONFIG0_SYNC_MASK BIT(15) +#define OA_CONFIG0_SYNC_POS 15 +#define OA_CONFIG0_TXFCSVE_MASK BIT(14) +#define OA_CONFIG0_TXFCSVE_POS 14 +#define OA_CONFIG0_CSARFE_MASK BIT(13) +#define OA_CONFIG0_CSARFE_POS 13 +#define OA_CONFIG0_ZARFE_MASK BIT(12) +#define OA_CONFIG0_ZARFE_POS 12 +#define OA_CONFIG0_TXCTHRESH_MASK GENMASK(11, 10) +#define OA_CONFIG0_TXCTHRESH_POS 10 +#define OA_CONFIG0_TXCTE_MASK BIT(9) +#define OA_CONFIG0_TXCTE_POS 9 +#define OA_CONFIG0_RXCTE_MASK BIT(8) +#define OA_CONFIG0_RXCTE_POS 8 +#define OA_CONFIG0_FTSE_MASK BIT(7) +#define OA_CONFIG0_FTSE_POS 7 +#define OA_CONFIG0_FTSS_MASK BIT(6) +#define OA_CONFIG0_FTSS_POS 6 +#define OA_CONFIG0_PROTE_MASK BIT(5) +#define OA_CONFIG0_PROTE_POS 5 +#define OA_CONFIG0_SEQE_MASK BIT(4) +#define OA_CONFIG0_SEQE_POS 4 +#define OA_CONFIG0_CPS_MASK GENMASK(2, 0) +#define OA_CONFIG0_CPS_POS 0 + +#define OA_STATUS0_MMS 0 +#define OA_STATUS0_ADDR 0x8U +#define OA_STATUS0_REGID OA_MAKE_REGID(OA_STATUS0_MMS, OA_STATUS0_ADDR) +#define OA_STATUS0_RESETC_MASK BIT(6) +#define OA_STATUS0_RESETC_POS 6 +#define OA_STATUS0_HDRE_MASK BIT(5) +#define OA_STATUS0_HDRE_POS 5 + +#define OA_BUFSTS_MMS 0 +#define OA_BUFSTS_ADDR 0xBU +#define OA_BUFSTS_REGID OA_MAKE_REGID(OA_BUFSTS_MMS, OA_BUFSTS_ADDR) + +#define OA_IMSK0_MMS 0 +#define OA_IMSK0_ADDR 0xCU +#define OA_IMSK0_REGID OA_MAKE_REGID(OA_IMSK0_MMS, OA_IMSK0_ADDR) +#define OA_IMSK0_DEF 0x1FBFU +#define OA_IMSK0_PHYINTM_MASK BIT(7) +#define OA_IMSK0_PHYINTM_POS 7 +#define OA_IMSK0_RXBOEM_MASK BIT(3) +#define OA_IMSK0_RXBOEM_POS 3 + +#define OA_PHY_CONTROL_MMS 0 +#define OA_PHY_CONTROL_ADDR 0xFF00U +#define OA_PHY_CONTROL_REGID OA_MAKE_REGID(OA_PHY_CONTROL_MMS, OA_PHY_CONTROL_ADDR) +#define OA_PHY_CONTROL_LCTL_POS 12 + +#define OA_PHY_STATUS_MMS 0 +#define OA_PHY_STATUS_ADDR 0xFF01U +#define OA_PHY_STATUS_REGID OA_MAKE_REGID(OA_PHY_STATUS_MMS, OA_PHY_STATUS_ADDR) + +/* registers specific to ncv7410 */ + +#define NCV_MAC_CONTROL0_MMS 1 +#define NCV_MAC_CONTROL0_ADDR 0x0U +#define NCV_MAC_CONTROL0_REGID OA_MAKE_REGID(NCV_MAC_CONTROL0_MMS, NCV_MAC_CONTROL0_ADDR) +#define NCV_MAC_CONTROL0_ADRF_POS 16 +#define NCV_MAC_CONTROL0_FCSA_POS 8 +#define NCV_MAC_CONTROL0_TXEN_POS 1 +#define NCV_MAC_CONTROL0_RXEN_POS 0 + +#define NCV_ADDRFILT0L_MMS 1 +#define NCV_ADDRFILT0L_ADDR 0x10U +#define NCV_ADDRFILT0L_REGID OA_MAKE_REGID(NCV_ADDRFILT0L_MMS, NCV_ADDRFILT0L_ADDR) + +#define NCV_ADDRFILT0H_MMS 1 +#define NCV_ADDRFILT0H_ADDR 0x11U +#define NCV_ADDRFILT0H_REGID OA_MAKE_REGID(NCV_ADDRFILT0H_MMS, NCV_ADDRFILT0H_ADDR) + +#define NCV_ADDRMASK0L_MMS 1 +#define NCV_ADDRMASK0L_ADDR 0x20U +#define NCV_ADDRMASK0L_REGID OA_MAKE_REGID(NCV_ADDRMASK0L_MMS, NCV_ADDRMASK0L_ADDR) + +#define NCV_ADDRMASK0H_MMS 1 +#define NCV_ADDRMASK0H_ADDR 0x21U +#define NCV_ADDRMASK0H_REGID OA_MAKE_REGID(NCV_ADDRMASK0H_MMS, NCV_ADDRMASK0H_ADDR) + +#define NCV_DIO_CONFIG_MMS 12 +#define NCV_DIO_CONFIG_ADDR 0x0012U +#define NCV_DIO_CONFIG_REGID OA_MAKE_REGID(NCV_DIO_CONFIG_MMS, NCV_DIO_CONFIG_ADDR) +#define NCV_DIO_CONFIG_DEF 0x6060 +#define NCV_DIO0_FUNC_POS 1 +#define NCV_DIO1_FUNC_POS 9 +#define NCV_DIO0_OUT_VAL_POS 0 +#define NCV_DIO1_OUT_VAL_POS 8 +#define NCV_DIO_TRISTATE_FUNC 0x0 +#define NCV_DIO_GPIO_FUNC 0x1 +#define NCV_DIO_SFD_TX_FUNC 0x2 +#define NCV_DIO_SFD_RX_FUNC 0x3 +#define NCV_DIO_LINK_CTRL_FUNC 0x4 +#define NCV_DIO_SFD_TXRX_FUNC 0xB +#define NCV_DIO_TXRX_FUNC 0xF + +#define NCV_MACID0_MMS 12 +#define NCV_MACID0_ADDR 0x1002U +#define NCV_MACID0_REGID OA_MAKE_REGID(NCV_MACID0_MMS, NCV_MACID0_ADDR) +#define NCV_MACID0_MASK GENMASK(15, 0) +#define NCV_MACID0_POS 0 + +#define NCV_MACID1_MMS 12 +#define NCV_MACID1_ADDR 0x1003U +#define NCV_MACID1_REGID OA_MAKE_REGID(NCV_MACID1_MMS, NCV_MACID1_ADDR) +#define NCV_MACID1_MASK GENMASK(7, 0) +#define NCV_MACID1_POS 0 + +/* OA Data Transaction and Control Transaction protocols bitfields */ + +/* Common bitfields */ + +#define OA_DNC_MASK BIT(31) +#define OA_DNC_POS 31 + +#define OA_HDRB_MASK BIT(30) +#define OA_HDRB_POS 30 + +#define OA_VS_MASK GENMASK(23, 22) +#define OA_VS_POS 22 + +#define OA_DV_MASK BIT(21) +#define OA_DV_POS 21 + +#define OA_SV_MASK BIT(20) +#define OA_SV_POS 20 + +#define OA_SWO_MASK GENMASK(19, 16) +#define OA_SWO_POS 16 + +#define OA_EV_MASK BIT(14) +#define OA_EV_POS 14 + +#define OA_EBO_MASK GENMASK(13, 8) +#define OA_EBO_POS 8 + +#define OA_P_MASK BIT(0) +#define OA_P_POS 0 + +/* Control Transaction Protocol header bitfields */ + +#define OA_WNR_MASK BIT(29) +#define OA_WNR_POS 29 + +#define OA_AID_MASK BIT(28) +#define OA_AID_POS 28 + +#define OA_MMS_MASK GENMASK(27, 24) +#define OA_MMS_POS 24 + +#define OA_ADDR_MASK GENMASK(23, 8) +#define OA_ADDR_POS 8 + +#define OA_LEN_MASK GENMASK(7, 1) +#define OA_LEN_POS 1 + +/* Transmit data header bitfields */ + +#define OA_SEQ_MASK BIT(30) +#define OA_SEQ_POS 30 + +#define OA_NORX_MASK BIT(29) +#define OA_NORX_POS 29 + +#define OA_TSC_MASK GENMASK(7, 6) +#define OA_TSC_POS 6 + +/* Receive data footer bitfields */ + +#define OA_EXST_MASK BIT(31) +#define OA_EXST_POS 31 + +#define OA_SYNC_MASK BIT(29) +#define OA_SYNC_POS 29 + +#define OA_RCA_MASK GENMASK(28, 24) +#define OA_RCA_POS 24 + +#define OA_FD_MASK BIT(15) +#define OA_FD_POS 15 + +#define OA_RTSA_MASK BIT(7) +#define OA_RTSA_POS 7 + +#define OA_RTSP_MASK BIT(6) +#define OA_RTSP_POS 6 + +#define OA_TXC_MASK GENMASK(5, 1) +#define OA_TXC_POS 1 + +#define _oa_control_field(f, fieldname) \ + ((int) ((f & OA_##fieldname##_MASK) >> OA_##fieldname##_POS)) + +#define oa_tx_credits(f) _oa_control_field(f, TXC) +#define oa_rx_available(f) _oa_control_field(f, RCA) +#define oa_header_bad(f) _oa_control_field(f, HDRB) +#define oa_ext_status(f) _oa_control_field(f, EXST) +#define oa_data_valid(f) _oa_control_field(f, DV) +#define oa_start_valid(f) _oa_control_field(f, SV) +#define oa_start_word_offset(f) _oa_control_field(f, SWO) +#define oa_end_valid(f) _oa_control_field(f, EV) +#define oa_end_byte_offset(f) _oa_control_field(f, EBO) +#define oa_frame_drop(f) _oa_control_field(f, FD) +#define oa_rx_frame_timestamp_added(f) _oa_control_field(f, RTSA) +#define oa_rx_frame_timestamp_parity(f) _oa_control_field(f, RTSP) +#define oa_mac_phy_sync(f) _oa_control_field(f, SYNC) + +#endif /* __DRIVERS_NET_NCV7410_H */ diff --git a/include/nuttx/net/ncv7410.h b/include/nuttx/net/ncv7410.h new file mode 100644 index 0000000000..92babc0c7d --- /dev/null +++ b/include/nuttx/net/ncv7410.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * include/nuttx/net/ncv7410.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NET_NCV7410_H +#define __INCLUDE_NUTTX_NET_NCV7410_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* A reference to a structure of this type must be passed to the NCV7410 + * driver when the driver is instantiated. This structure provides + * information about the configuration of the NCV7410. + * + * Memory for this structure is provided by the caller. It is not copied by + * the driver and is presumed to persist while the driver is active. + */ + +struct ncv7410_config_s +{ + uint32_t id; + + /* TODO: include hooks for interrupt logic */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv7410_initialize + * + * Description: + * Initialize the Ethernet driver. + * + * Input Parameters: + * spi - reference to the SPI driver state data + * irq - irq number of the pin connected to MAC-PHY's interrupt signal + * + * Returned Value: + * On success OK is returned, otherwise negated errno is returned. + * + ****************************************************************************/ + +struct spi_dev_s; /* forward declaration, see nuttx/spi/spi.h */ +int ncv7410_initialize(FAR struct spi_dev_s *spi, int irq, + struct ncv7410_config_s *config); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_NET_NCV7410_H */