This is an automated email from the ASF dual-hosted git repository.
xiaoxiang 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 bf54a5ae50 driver/net/lan9250: Add LAN9250 driver(SPI and QSPI mode)
bf54a5ae50 is described below
commit bf54a5ae50d01b875d4d2a6ba2364282e2dcc4f3
Author: Dong Heng <[email protected]>
AuthorDate: Thu Oct 26 16:42:51 2023 +0800
driver/net/lan9250: Add LAN9250 driver(SPI and QSPI mode)
---
boards/xtensa/esp32s3/common/src/Make.defs | 4 +
boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c | 245 ++
.../esp32s3-devkit/configs/eth_lan9250/defconfig | 75 +
.../xtensa/esp32s3/esp32s3-devkit/include/board.h | 15 +
.../esp32s3/esp32s3-devkit/src/esp32s3-devkit.h | 21 +
.../esp32s3/esp32s3-devkit/src/esp32s3_bringup.c | 9 +
drivers/net/CMakeLists.txt | 4 +
drivers/net/Kconfig | 63 +
drivers/net/Make.defs | 4 +
drivers/net/lan9250.c | 2452 ++++++++++++++++++++
drivers/net/lan9250.h | 628 +++++
include/nuttx/net/lan9250.h | 125 +
12 files changed, 3645 insertions(+)
diff --git a/boards/xtensa/esp32s3/common/src/Make.defs
b/boards/xtensa/esp32s3/common/src/Make.defs
index 47196bf462..dbb2b82ca5 100644
--- a/boards/xtensa/esp32s3/common/src/Make.defs
+++ b/boards/xtensa/esp32s3/common/src/Make.defs
@@ -56,6 +56,10 @@ ifeq ($(CONFIG_ESP32S3_OTG),y)
CSRCS += esp32s3_board_usb.c
endif
+ifeq ($(CONFIG_NET_LAN9250),y)
+ CSRCS += esp32s3_lan9250.c
+endif
+
DEPPATH += --dep-path src
VPATH += :src
CFLAGS +=
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
diff --git a/boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
b/boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
new file mode 100644
index 0000000000..8981a24b98
--- /dev/null
+++ b/boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
@@ -0,0 +1,245 @@
+/****************************************************************************
+ * boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
+ *
+ * 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 <debug.h>
+#include <errno.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <nuttx/irq.h>
+#include <nuttx/net/lan9250.h>
+#include <arch/board/board.h>
+
+#include "xtensa.h"
+#include "esp32s3_gpio.h"
+#ifdef CONFIG_LAN9250_SPI
+#include "esp32s3_spi.h"
+#else
+#include "esp32s3_qspi.h"
+#endif
+#include "hardware/esp32s3_efuse.h"
+#include "hardware/esp32s3_gpio_sigmap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Protototypes
+ ****************************************************************************/
+
+static int lan9250_attach(const struct lan9250_lower_s *lower,
+ xcpt_t handler, void *arg);
+static void lan9250_enable(const struct lan9250_lower_s *lower);
+static void lan9250_disable(const struct lan9250_lower_s *lower);
+static void lan9250_getmac(const struct lan9250_lower_s *lower,
+ uint8_t *mac);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct lan9250_lower_s g_lan9250_lower =
+{
+ .attach = lan9250_attach,
+ .enable = lan9250_enable,
+ .disable = lan9250_disable,
+ .getmac = lan9250_getmac
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_attach
+ *
+ * Description:
+ * Attach LAN9250 interrupt.
+ *
+ * Input Parameters:
+ * lower - A reference to the LAN9250 low-level object data.
+ * handler - Interrupt handle
+ * arg - Interrupt private argument
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_attach(const struct lan9250_lower_s *lower,
+ xcpt_t handler, void *arg)
+{
+ int ret;
+ int irq = ESP32S3_PIN2IRQ(LAN9250_IRQ);
+
+ ret = irq_attach(irq, handler, arg);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: irq_attach() failed: %d\n", ret);
+ return ret;
+ }
+
+ ninfo("Attach the interrupt\n");
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: lan9250_enable
+ *
+ * Description:
+ * Enable LAN9250 interrupt.
+ *
+ * Input Parameters:
+ * lower - A reference to the LAN9250 low-level object data.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_enable(const struct lan9250_lower_s *lower)
+{
+ int irq = ESP32S3_PIN2IRQ(LAN9250_IRQ);
+
+ /* Configure the interrupt for rising and falling edges */
+
+ esp32s3_gpioirqenable(irq, GPIO_INTR_LOW_LEVEL);
+ ninfo("Enable the interrupt\n");
+}
+
+/****************************************************************************
+ * Name: lan9250_disable
+ *
+ * Description:
+ * Disable LAN9250 interrupt.
+ *
+ * Input Parameters:
+ * lower - A reference to the LAN9250 low-level object data.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_disable(const struct lan9250_lower_s *lower)
+{
+ int irq = ESP32S3_PIN2IRQ(LAN9250_IRQ);
+
+ ninfo("Disable the interrupt\n");
+ esp32s3_gpioirqdisable(irq);
+}
+
+/****************************************************************************
+ * Name: lan9250_getmac
+ *
+ * Description:
+ * Retrieves the ESP32-S3 MAC address to be set in the LAN9250 driver.
+ *
+ * Input Parameters:
+ * lower - A reference to the LAN9250 low-level object data.
+ * mac - A pointer to a buffer where the MAC address will be stored.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_getmac(const struct lan9250_lower_s *lower, uint8_t *mac)
+{
+ uint32_t regval[2];
+ uint8_t *data = (uint8_t *)regval;
+
+ regval[0] = getreg32(EFUSE_RD_MAC_SPI_SYS_0_REG);
+ regval[1] = getreg32(EFUSE_RD_MAC_SPI_SYS_1_REG);
+
+ for (int i = 0; i < 6; i++)
+ {
+ mac[i] = data[i];
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_lan9250_initialize
+ *
+ * Description:
+ * This function is called by platform-specific setup logic to initialize
+ * the LAN9250 device. This function will register the driver
+ * as a network device.
+ *
+ * Input Parameters:
+ * port - The SPI port used for the device
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_lan9250_initialize(int port)
+{
+ int ret;
+#ifdef CONFIG_LAN9250_SPI
+ struct spi_dev_s *dev;
+#else
+ struct qspi_dev_s *dev;
+#endif
+
+ esp32s3_configgpio(LAN9250_IRQ, INPUT_FUNCTION_2 | PULLUP);
+ esp32s3_configgpio(LAN9250_RST, OUTPUT_FUNCTION_2 | PULLUP);
+
+#ifdef CONFIG_LAN9250_SPI
+ dev = esp32s3_spibus_initialize(port);
+ if (!dev)
+ {
+ nerr("ERROR: Failed to initialize SPI port %d\n", port);
+ return -ENODEV;
+ }
+#else
+ dev = esp32s3_qspibus_initialize(port);
+ if (!dev)
+ {
+ nerr("ERROR: Failed to initialize QSPI port %d\n", port);
+ return -ENODEV;
+ }
+#endif
+
+ ret = lan9250_initialize(dev, &g_lan9250_lower);
+ if (ret != 0)
+ {
+ nerr("ERROR: Failed to initialize LAN9250 ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/eth_lan9250/defconfig
b/boards/xtensa/esp32s3/esp32s3-devkit/configs/eth_lan9250/defconfig
new file mode 100644
index 0000000000..798c4c7d4e
--- /dev/null
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/eth_lan9250/defconfig
@@ -0,0 +1,75 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that
includes your
+# modifications.
+#
+# CONFIG_ARCH_LEDS is not set
+# CONFIG_ESP32S3_RTC is not set
+# CONFIG_NDEBUG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_SPI_EXCHANGE is not set
+CONFIG_ALLOW_BSD_COMPONENTS=y
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32s3-devkit"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32S3_DEVKIT=y
+CONFIG_ARCH_CHIP="esp32s3"
+CONFIG_ARCH_CHIP_ESP32S3=y
+CONFIG_ARCH_CHIP_ESP32S3WROOM1=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_DEFAULT_TASK_STACKSIZE=4096
+CONFIG_ESP32S3_GPIO_IRQ=y
+CONFIG_ESP32S3_SPI2=y
+CONFIG_ESP32S3_SPI_SWCS=y
+CONFIG_ESP32S3_UART0=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INIT_STACKSIZE=8192
+CONFIG_INTELHEX_BINARY=y
+CONFIG_IOB_BUFSIZE=1514
+CONFIG_IOB_NBUFFERS=5
+CONFIG_LAN9250_FREQUENCY=40000000
+CONFIG_LAN9250_SPI_EXCLUSIVE=y
+CONFIG_NAME_MAX=48
+CONFIG_NET=y
+CONFIG_NETDB_DNSCLIENT=y
+CONFIG_NETDEV_LATEINIT=y
+CONFIG_NETUTILS_IPERF=y
+CONFIG_NET_ARP_SEND=y
+CONFIG_NET_ETH_PKTSIZE=1518
+CONFIG_NET_ICMP=y
+CONFIG_NET_ICMP_SOCKET=y
+CONFIG_NET_LAN9250=y
+CONFIG_NET_TCP=y
+CONFIG_NET_UDP=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=2048
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_PTHREAD_MUTEX_TYPES=y
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SIG_DEFAULT=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSLOG_BUFFER=y
+CONFIG_SYSTEM_DHCPC_RENEW=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_PING=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
b/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
index 54e89c98f5..9c2690cece 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
@@ -49,4 +49,19 @@
#define BOARD_NGPIOIN 1 /* Amount of GPIO Input without Interruption */
#define BOARD_NGPIOINT 1 /* Amount of GPIO Input w/ Interruption pins */
+/* LAN9250 SPI and GPIO pins configuration */
+
+#ifdef CONFIG_NET_LAN9250
+
+# define LAN9250_SPI 2
+
+/* LAN9250 IRQ pin */
+
+# define LAN9250_IRQ 38
+
+/* LAN9250 reset pin */
+
+# define LAN9250_RST 17
+#endif
+
#endif /* __BOARDS_XTENSA_ESP32S3_ESP32S3_DEVKIT_INCLUDE_BOARD_H */
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
index 62b9acfc5f..215a69468a 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
@@ -210,5 +210,26 @@ int esp32s3_pwm_setup(void);
int esp32s3_twai_setup(void);
#endif
+/****************************************************************************
+ * Name: esp32s3_lan9250_initialize
+ *
+ * Description:
+ * This function is called by platform-specific setup logic to initialize
+ * the LAN9250 device. This function will register the driver
+ * as a network device.
+ *
+ * Input Parameters:
+ * port - The SPI port used for the device
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno value is
+ * returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_LAN9250
+int esp32s3_lan9250_initialize(int port);
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_XTENSA_ESP32S3_ESP32S3_DEVKIT_SRC_ESP32S3_DEVKIT_H */
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
index 23e8ed687f..51e8c8442c 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
@@ -38,6 +38,7 @@
#include <errno.h>
#include <nuttx/fs/fs.h>
#include <nuttx/himem/himem.h>
+#include <arch/board/board.h>
#ifdef CONFIG_ESP32S3_TIMER
# include "esp32s3_board_tim.h"
@@ -388,6 +389,14 @@ int esp32s3_bringup(void)
}
#endif
+#ifdef CONFIG_NET_LAN9250
+ ret = esp32s3_lan9250_initialize(LAN9250_SPI);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to initialize SPI ethernet LAN9250.\n");
+ }
+#endif
+
/* If we got here then perhaps not all initialization was successful, but
* at least enough succeeded to bring-up NSH with perhaps reduced
* capabilities.
diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt
index f399251949..9d5492d249 100644
--- a/drivers/net/CMakeLists.txt
+++ b/drivers/net/CMakeLists.txt
@@ -75,6 +75,10 @@ if(CONFIG_NET)
list(APPEND SRCS w5500.c)
endif()
+ if(CONFIG_NET_LAN9250)
+ list(APPEND SRCS lan9250.c)
+ endif()
+
if(CONFIG_ARCH_PHY_INTERRUPT)
list(APPEND SRCS phy_notify.c)
endif()
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d1f87797ab..c34bc9263a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -428,6 +428,69 @@ config NET_W5500_NINTERFACES
endif # W5500
+menuconfig NET_LAN9250
+ bool "Microchip LAN9250 support"
+ default n
+ select SPI
+ select ARCH_HAVE_NETDEV_STATISTICS
+ ---help---
+ Enable LAN9250 SPI Ethernet driver.
+
+if NET_LAN9250
+
+choice LAN9250_INTERFACE
+ prompt "Select interface"
+ default LAN9250_SPI
+ ---help---
+ Select LAN9250 interface: SPI(4-line) or SQI(6-line).
+
+config LAN9250_SPI
+ bool "SPI"
+
+config LAN9250_SQI
+ bool "SQI"
+endchoice
+
+config LAN9250_SPI_EXCLUSIVE
+ bool "SPI Exclusive"
+ default n
+ ---help---
+ The SPI is exclusive for LAN9250.
+
+config LAN9250_SPIMODE
+ int "SPI mode"
+ default 0
+ ---help---
+ Controls the SPI mode.
+
+config LAN9250_FREQUENCY
+ int "SPI frequency"
+ default 10000000
+ ---help---
+ Define to use a different bus frequency.
+
+config LAN9250_HALFDUPPLEX
+ bool "Enable half duplex"
+ default n
+ ---help---
+ Default is full duplex.
+
+config LAN9250_DUMPPACKET
+ bool "Dump Packets"
+ default n
+ ---help---
+ If selected, the LAN9250 driver will dump the contents of each
+ packet to the console.
+
+config LAN9250_REGDEBUG
+ bool "Register-Level Debug"
+ default n
+ depends on DEBUG_FEATURES && DEBUG_NET
+ ---help---
+ Enable very low-level register access debug.
+
+endif # NET_LAN9250
+
if ARCH_HAVE_PHY
comment "External Ethernet PHY Device Support"
diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs
index 070df18e55..c1f65a214d 100644
--- a/drivers/net/Make.defs
+++ b/drivers/net/Make.defs
@@ -76,6 +76,10 @@ ifeq ($(CONFIG_NET_W5500),y)
CSRCS += w5500.c
endif
+ifeq ($(CONFIG_NET_LAN9250),y)
+ CSRCS += lan9250.c
+endif
+
ifeq ($(CONFIG_ARCH_PHY_INTERRUPT),y)
CSRCS += phy_notify.c
endif
diff --git a/drivers/net/lan9250.c b/drivers/net/lan9250.c
new file mode 100644
index 0000000000..e2bba33954
--- /dev/null
+++ b/drivers/net/lan9250.c
@@ -0,0 +1,2452 @@
+/****************************************************************************
+ * drivers/net/lan9250.c
+ *
+ * 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 <stdint.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/clock.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/ip.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/lan9250.h>
+
+#ifdef CONFIG_NET_PKT
+# include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_LAN9250_SPI
+# include <nuttx/spi/spi.h>
+#else
+# include <nuttx/spi/qspi.h>
+#endif
+
+#include "lan9250.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* LAN9250 SPI clock */
+
+#define LAN9250_FREQUENCY CONFIG_LAN9250_FREQUENCY
+
+/* LAN9250 read and write command */
+
+#ifdef CONFIG_LAN9250_SPI
+# if LAN9250_FREQUENCY > (30 * 1000 * 1000)
+# define LAN9250_SPI_READ LAN9250_SPI_CMD_FREAD
+# else
+# define LAN9250_SPI_READ LAN9250_SPI_CMD_READ
+# endif
+
+# define LAN9250_SPI_WRITE LAN9250_SPI_CMD_WRITE
+#else
+# define LAN9250_SPI_READ LAN9250_QSPI_CMD_READ
+# define LAN9250_SPI_WRITE LAN9250_QSPI_CMD_WRITE
+
+# define LAN9250_SPI_ENABLE_SQI LAN9250_SPI_CMD_ENABLE_SQI
+#endif
+
+/**
+ * LAN9250 interrupt trigger source:
+ *
+ * - PHY for checking link up or down
+ * - TX data FIFO available
+ * - RX data FIFO reaches programmed level
+ */
+
+#define LAN9250_INT_SOURCE (IER_PHY | IER_TDFA | IER_RSFL)
+
+/* The low-priority work queue is preferred. If it is not enabled, LPWORK
+ * will be the same as HPWORK.
+ *
+ * NOTE: However, the network should NEVER run on the high priority work
+ * queue! That queue is intended only to service short back end interrupt
+ * processing that never suspends. Suspending the high priority work queue
+ * may bring the system to its knees!
+ */
+
+#define LAN9250_WORK LPWORK
+
+/* Timing *******************************************************************/
+
+/* Reset timeout in second */
+
+#define LAN9250_RESET_TIMEOUT (5)
+
+/* TX timeout = 1 minute */
+
+#define LAN9250_TX_TIMEOUT (60 * CLK_TCK)
+
+/* Poll timeout */
+
+#define LAN9250_POLL_TIMEOUT MSEC2TICK(50)
+
+/* Read/Write MAC register timeout in second */
+
+#define LAN9250_MAC_TIMEOUT 2
+
+/* Read/Write PHY register timeout in second */
+
+#define LAN9250_PHY_TIMEOUT 2
+
+/* Read/Write PHY register timeout in millisecond */
+
+#define LAN9250_SQI_TIMEOUT 20
+
+/* Packet Memory ************************************************************/
+
+/* Misc. Helper Macros ******************************************************/
+
+#define LAN9250_ALIGN(v) (((v) + 3) & (~3))
+
+/* Packet buffer size with 4-CRC */
+
+#define LAN9250_PKTBUF_SIZE LAN9250_ALIGN(MAX_NETDEV_PKTSIZE + \
+ CONFIG_NET_GUARDSIZE + \
+ 4)
+
+/* This is a helper pointer for accessing the contents of Ethernet header */
+
+#define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
+
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_LAN9250_REGDEBUG
+# define lan9250_setreg_dump(a, v) \
+ syslog(LOG_DEBUG, "LAN9250 REG: 0x%04x<-0x%08x\n", a, v)
+# define lan9250_getreg_dump(a, v) \
+ syslog(LOG_DEBUG, "LAN9250 REG: 0x%04x->0x%08x\n", a, v)
+# define lan9250_setmacreg_dump(a, v) \
+ syslog(LOG_DEBUG, "LAN9250 MAC: 0x%02x<-0x%08x\n", a, v)
+# define lan9250_getmacreg_dump(a, v) \
+ syslog(LOG_DEBUG, "LAN9250 MAC: 0x%02x->0x%08x\n", a, v)
+# define lan9250_setphyreg_dump(a, v) \
+ syslog(LOG_DEBUG, "LAN9250 PHY: 0x%02x<-0x%08x\n", a, v)
+# define lan9250_getphyreg_dump(a, v) \
+ syslog(LOG_DEBUG, "LAN9250 PHY: 0x%02x->0x%08x\n", a, v)
+# define lan9250_buffer_dump(c, b, s) \
+ syslog(LOG_DEBUG, "LAN9250 BUF: cmd: %04x buffer: %p length: %d\n", c, b, s)
+#else
+# define lan9250_setreg_dump(a, v)
+# define lan9250_getreg_dump(a, v)
+# define lan9250_setmacreg_dump(a, v)
+# define lan9250_getmacreg_dump(a, v)
+# define lan9250_setphyreg_dump(a, v)
+# define lan9250_getphyreg_dump(a, v)
+# define lan9250_buffer_dump(c, b, s)
+#endif
+
+/* CONFIG_LAN9250_DUMPPACKET will dump the contents of each packet. */
+
+#ifdef CONFIG_LAN9250_DUMPPACKET
+# define lan9250_dump_buf(m, a, n) lib_dumpbuffer(m, a, n)
+#else
+# define lan9250_dump_buf(m, a, n)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The lan9250_driver_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct lan9250_driver_s
+{
+ /* Low-level MCU-specific support */
+
+ const struct lan9250_lower_s *lower;
+
+ /* This is the contained (Q)SPI driver instance */
+
+#ifdef CONFIG_LAN9250_SPI
+ struct spi_dev_s *spi;
+#else
+ bool sqi_mode;
+ struct qspi_dev_s *qspi;
+#endif
+
+ bool tx_available; /* TX is available */
+
+ /* Read/Write buffer for SPI transmission */
+
+ uint32_t pktbuf[LAN9250_PKTBUF_SIZE / 4];
+
+ struct wdog_s txtout_timer; /* TX timeout timer */
+ struct work_s txtout_work; /* Tx timeout work */
+ struct work_s txpoll_work; /* TX poll work */
+ struct work_s irq_work; /* Interrupt work */
+
+ /* This holds the information visible to the NuttX network */
+
+ struct net_driver_s dev; /* Interface understood by the network */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Driver status structure */
+
+static struct lan9250_driver_s g_lan9250;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Low-level SPI helpers */
+
+static inline void lan9250_config_spi(FAR struct lan9250_driver_s *priv);
+static void lan9250_lock_spi(FAR struct lan9250_driver_s *priv);
+static inline void lan9250_unlock_spi(FAR struct lan9250_driver_s *priv);
+
+/* SPI control register access */
+
+static uint32_t lan9250_get_reg(FAR struct lan9250_driver_s *priv,
+ uint16_t address);
+static void lan9250_set_reg(FAR struct lan9250_driver_s *priv,
+ uint16_t address, uint32_t data);
+static void lan9250_wait_ready(FAR struct lan9250_driver_s *priv,
+ uint16_t address, uint32_t mask,
+ uint32_t expected, uint32_t timeout);
+
+/* MAC register access */
+
+static uint32_t lan9250_get_macreg(FAR struct lan9250_driver_s *priv,
+ uint8_t address);
+static void lan9250_set_macreg(FAR struct lan9250_driver_s *priv,
+ uint8_t address, uint32_t data);
+static void lan9250_wait_mac_ready(FAR struct lan9250_driver_s *priv,
+ uint8_t address, uint32_t mask,
+ uint32_t expected, uint32_t timeout);
+
+/* PHY register access */
+
+static uint16_t lan9250_get_phyreg(FAR struct lan9250_driver_s *priv,
+ uint8_t phyaddr);
+static void lan9250_set_phyreg(FAR struct lan9250_driver_s *priv,
+ uint8_t phyaddr, uint16_t phydata);
+
+/* SPI buffer transfers */
+
+static void lan9250_recv_buffer(FAR struct lan9250_driver_s *priv,
+ FAR uint8_t *buffer, size_t buflen);
+static inline void lan9250_send_buffer(FAR struct lan9250_driver_s *priv,
+ FAR const uint8_t *buffer,
+ size_t buflen);
+
+/* Misc handling */
+
+#ifdef CONFIG_LAN9250_SQI
+static void lan9250_enable_sqi(FAR struct lan9250_driver_s *priv);
+#endif
+static inline void lan9250_sw_reset(FAR struct lan9250_driver_s *priv);
+static void lan9250_set_txavailabe(FAR struct lan9250_driver_s *priv,
+ bool enable);
+static int lan9250_reset(FAR struct lan9250_driver_s *priv);
+static void lan9250_set_macaddr(FAR struct lan9250_driver_s *priv);
+
+/* Common TX logic */
+
+static int lan9250_transmit(FAR struct lan9250_driver_s *priv);
+static int lan9250_txpoll(FAR struct net_driver_s *dev);
+
+/* Interrupt handling */
+
+static void lan9250_netdev_rx(FAR struct lan9250_driver_s *priv);
+static void lan9250_phy_isr(FAR struct lan9250_driver_s *priv);
+static void lan9250_txavailable_isr(FAR struct lan9250_driver_s *priv);
+static void lan9250_rxdone_isr(FAR struct lan9250_driver_s *priv);
+static int lan9250_interrupt(int irq, FAR void *context, FAR void *arg);
+
+/* Watchdog timer expirations */
+
+static void lan9250_txtout_timercb(wdparm_t arg);
+
+/* Driver worker */
+
+static void lan9250_txavail_work(FAR void *arg);
+static void lan9250_txtout_worker(FAR void *arg);
+static void lan9250_int_worker(FAR void *arg);
+
+/* NuttX callback functions */
+
+static int lan9250_ifup(FAR struct net_driver_s *dev);
+static int lan9250_ifdown(FAR struct net_driver_s *dev);
+static int lan9250_txavail(FAR struct net_driver_s *dev);
+#ifdef CONFIG_NET_MCASTGROUP
+static int lan9250_addmac(FAR struct net_driver_s *dev,
+ FAR const uint8_t *mac);
+static int lan9250_rmmac(FAR struct net_driver_s *dev,
+ FAR const uint8_t *mac);
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_config_spi
+ *
+ * Description:
+ * Configure the SPI for use with the LAN9250
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_config_spi(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_LAN9250_SPI
+ FAR struct spi_dev_s *spi = priv->spi;
+
+ /* Configure SPI for the LAN9250. */
+
+ SPI_SETMODE(spi, CONFIG_LAN9250_SPIMODE);
+ SPI_SETBITS(spi, 8);
+ SPI_HWFEATURES(spi, 0);
+ SPI_SETFREQUENCY(spi, LAN9250_FREQUENCY);
+#else
+ FAR struct qspi_dev_s *qspi = priv->qspi;
+
+ /* Configure QSPI for the LAN9250. */
+
+ QSPI_SETMODE(qspi, CONFIG_LAN9250_SPIMODE);
+ QSPI_SETBITS(qspi, 8);
+ QSPI_HWFEATURES(qspi, 0);
+ QSPI_SETFREQUENCY(qspi, LAN9250_FREQUENCY);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_lock_spi
+ *
+ * Description:
+ * Select the SPI, locking it and re-configuring it if necessary.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_lock_spi(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_LAN9250_SPI
+
+ /* Lock the SPI bus in case there are multiple devices or tasks competing
+ * for the SPI bus.
+ */
+
+ SPI_LOCK(priv->spi, true);
+#else
+
+ /* Lock the QSPI bus in case there are multiple devices or tasks competing
+ * for the QSPI bus.
+ */
+
+ QSPI_LOCK(priv->qspi, true);
+#endif
+
+ /* Now make sure that the (Q)SPI bus is configured for the LAN9250 (it
+ * might have gotten configured for a different device while unlocked)
+ */
+
+#ifndef CONFIG_LAN9250_SPI_EXCLUSIVE
+ lan9250_config_spi(priv);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_unlock_spi
+ *
+ * Description:
+ * De-select the SPI
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_unlock_spi(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_LAN9250_SPI
+
+ /* Relinquish the lock on the bus. */
+
+ SPI_LOCK(priv->spi, false);
+#else
+
+ /* Relinquish the lock on the bus. */
+
+ QSPI_LOCK(priv->qspi, false);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_get_reg
+ *
+ * Description:
+ * Read a global register value.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - Register address
+ *
+ * Returned Value:
+ * The value read from the register.
+ *
+ ****************************************************************************/
+
+static uint32_t lan9250_get_reg(FAR struct lan9250_driver_s *priv,
+ uint16_t address)
+{
+#ifdef CONFIG_LAN9250_SPI
+# if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+ uint8_t cmd_buffer[4];
+# else
+ uint8_t cmd_buffer[3];
+# endif
+ uint32_t regval;
+
+ cmd_buffer[0] = LAN9250_SPI_READ;
+ cmd_buffer[1] = (uint8_t)(address >> 8);
+ cmd_buffer[2] = (uint8_t)(address >> 0);
+# if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+ cmd_buffer[3] = 0xff; /* SPI read dummy */
+# endif
+
+ /* Select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+ /* Send the read command and register address */
+
+ SPI_SNDBLOCK(priv->spi, cmd_buffer, sizeof(cmd_buffer));
+
+ /* Receive register value, total 4 bytes */
+
+ SPI_RECVBLOCK(priv->spi, ®val, 4);
+
+ /* De-select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+ struct qspi_cmdinfo_s cmdinfo;
+ uint32_t regval;
+ uint32_t buffer[2];
+ int ret;
+
+ cmdinfo.cmd = LAN9250_SPI_READ;
+ cmdinfo.addr = address;
+ cmdinfo.addrlen = sizeof(address);
+ cmdinfo.buffer = buffer;
+ cmdinfo.buflen = sizeof(buffer); /* 4 dummy bytes */
+ cmdinfo.flags = QSPICMD_ADDRESS | QSPICMD_READDATA;
+ if (priv->sqi_mode)
+ {
+ cmdinfo.flags |= QSPICMD_IQUAD;
+ }
+
+ ret = QSPI_COMMAND(priv->qspi, &cmdinfo);
+ DEBUGASSERT(ret == 0);
+
+ regval = buffer[1];
+#endif
+
+ lan9250_getreg_dump(address, regval);
+ return regval;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_reg
+ *
+ * Description:
+ * Write to a global register.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - Register address
+ * data - The data to send
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_reg(FAR struct lan9250_driver_s *priv,
+ uint16_t address,
+ uint32_t data)
+{
+#ifdef CONFIG_LAN9250_SPI
+ uint8_t cmd_buffer[3];
+
+ DEBUGASSERT(priv && priv->spi);
+
+ cmd_buffer[0] = LAN9250_SPI_WRITE;
+ cmd_buffer[1] = (uint8_t)(address >> 8);
+ cmd_buffer[2] = (uint8_t)(address >> 0);
+
+ /* Select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+ /* Send the read command and register address */
+
+ SPI_SNDBLOCK(priv->spi, cmd_buffer, sizeof(cmd_buffer));
+
+ /* Receive register value, total 4 bytes */
+
+ SPI_SNDBLOCK(priv->spi, &data, 4);
+
+ /* De-select LAN9250 chip. */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+ struct qspi_cmdinfo_s cmdinfo;
+ int ret;
+
+ cmdinfo.cmd = LAN9250_SPI_WRITE;
+ cmdinfo.addr = address;
+ cmdinfo.addrlen = sizeof(address);
+ cmdinfo.buffer = &data;
+ cmdinfo.buflen = sizeof(data);
+ cmdinfo.flags = QSPICMD_ADDRESS | QSPICMD_WRITEDATA;
+ if (priv->sqi_mode)
+ {
+ cmdinfo.flags |= QSPICMD_IQUAD;
+ }
+
+ ret = QSPI_COMMAND(priv->qspi, &cmdinfo);
+ DEBUGASSERT(ret == 0);
+#endif
+
+ lan9250_setreg_dump(address, data);
+}
+
+/****************************************************************************
+ * Name: lan9250_wait_ready
+ *
+ * Description:
+ * Wait until LAN9250 is ready.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - Register address
+ * mask - Register value mask
+ * expected - Expected register value
+ * second - Wait timeout in second
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_wait_ready(FAR struct lan9250_driver_s *priv,
+ uint16_t address, uint32_t mask,
+ uint32_t expected, uint32_t second)
+{
+ clock_t tout_ticks = clock_systime_ticks() + SEC2TICK(second);
+ bool timeout = false;
+
+ while (1)
+ {
+ if ((lan9250_get_reg(priv, address) & mask) == expected)
+ {
+ break;
+ }
+ else if (clock_systime_ticks() > tout_ticks)
+ {
+ timeout = true;
+ break;
+ }
+ }
+
+ if (timeout)
+ {
+ nerr("ERROR: wait register:0x%02x, mask:0x%08x, expected:0x%08x\n",
+ address, mask, expected);
+ }
+}
+
+/****************************************************************************
+ * Name: lan9250_get_macreg
+ *
+ * Description:
+ * Read a MAC register value.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - MAC register address
+ *
+ * Returned Value:
+ * The value read from the MAC register.
+ *
+ ****************************************************************************/
+
+static uint32_t lan9250_get_macreg(FAR struct lan9250_driver_s *priv,
+ uint8_t address)
+{
+ uint32_t regval = address | HMCSRICR_CSRB | HMCSRICR_RNW;
+
+ /* Wait for MAC to be ready and send reading register command */
+
+ lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+ LAN9250_MAC_TIMEOUT);
+ lan9250_set_reg(priv, LAN9250_HMCSRICR, regval);
+
+ /* Wait for MAC to be ready and read register value */
+
+ lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+ LAN9250_MAC_TIMEOUT);
+ regval = lan9250_get_reg(priv, LAN9250_HMCSRIDR);
+
+ lan9250_getmacreg_dump(address, regval);
+ return regval;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_macreg
+ *
+ * Description:
+ * Write to a MAC register.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * cmd - MAC register address
+ * data - The data to send
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_macreg(FAR struct lan9250_driver_s *priv,
+ uint8_t address, uint32_t data)
+{
+ uint32_t regval = address | HMCSRICR_CSRB;
+
+ lan9250_setmacreg_dump(address, data);
+
+ /* Wait for MAC to be ready and send writing register command and data */
+
+ lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+ LAN9250_MAC_TIMEOUT);
+ lan9250_set_reg(priv, LAN9250_HMCSRIDR, data);
+ lan9250_set_reg(priv, LAN9250_HMCSRICR, regval);
+
+ /* Wait until writing MAC is done */
+
+ lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+ LAN9250_MAC_TIMEOUT);
+}
+
+/****************************************************************************
+ * Name: lan9250_wait_mac_ready
+ *
+ * Description:
+ * Wait until LAN9250 MAC is ready
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - MAC register address
+ * mask - MAC register value mask
+ * expected - Expected MAC register value
+ * timeout - Wait timeout in second
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_wait_mac_ready(FAR struct lan9250_driver_s *priv,
+ uint8_t address, uint32_t mask,
+ uint32_t expected, uint32_t second)
+{
+ clock_t tout_ticks = clock_systime_ticks() + SEC2TICK(second);
+ bool timeout = false;
+
+ while (1)
+ {
+ if ((lan9250_get_macreg(priv, address) & mask) == expected)
+ {
+ break;
+ }
+ else if (clock_systime_ticks() > tout_ticks)
+ {
+ timeout = true;
+ break;
+ }
+ }
+
+ if (timeout)
+ {
+ nerr("ERROR: wait MAC register:0x%02x, mask:0x%08x, expected:0x%08x\n",
+ address, mask, expected);
+ }
+}
+
+/****************************************************************************
+ * Name: lan9250_get_phyreg
+ *
+ * Description:
+ * Read 16-bits of PHY data.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - The PHY register address
+ *
+ * Returned Value:
+ * 16-bit value read from the PHY
+ *
+ ****************************************************************************/
+
+static uint16_t lan9250_get_phyreg(FAR struct lan9250_driver_s *priv,
+ uint8_t address)
+{
+ uint32_t regval = (1 << HMACMIIAR_PHYA_S) |
+ (address << HMACMIIAR_MIIRX_S);
+
+ /* Wait PHY to be ready and send reading register command */
+
+ lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+ LAN9250_PHY_TIMEOUT);
+ lan9250_set_macreg(priv, LAN9250_HMACMIIAR, regval);
+
+ /* Wait PHY to be ready and read register value */
+
+ lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+ LAN9250_PHY_TIMEOUT);
+ regval = lan9250_get_macreg(priv, LAN9250_HMACMIIDR);
+
+ lan9250_getphyreg_dump(address, regval);
+
+ return regval;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_phyreg
+ *
+ * Description:
+ * Write 16-bits of PHY data.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * address - The PHY register address
+ * data - 16-bit data to write to the PHY
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_phyreg(FAR struct lan9250_driver_s *priv,
+ uint8_t address,
+ uint16_t data)
+{
+ uint32_t regval = (1 << HMACMIIAR_PHYA_S) |
+ (address << HMACMIIAR_MIIRX_S) |
+ HMACMIIAR_MIIW;
+
+ DEBUGASSERT((address & (HMACMIIAR_MIIRX_M >> HMACMIIAR_MIIRX_S))
+ == address);
+
+ lan9250_setphyreg_dump(address, data);
+
+ /* Wait PHY to be ready and send writing register command and data */
+
+ lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+ LAN9250_PHY_TIMEOUT);
+ lan9250_set_macreg(priv, LAN9250_HMACMIIDR, data);
+ lan9250_set_macreg(priv, LAN9250_HMACMIIAR, regval);
+
+ /* Wait PHY until writing is done */
+
+ lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+ LAN9250_PHY_TIMEOUT);
+}
+
+/****************************************************************************
+ * Name: lan9250_recv_buffer
+ *
+ * Description:
+ * Read a buffer of data.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * buffer - A pointer to the buffer to read into
+ * buflen - The number of bytes to read
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_recv_buffer(FAR struct lan9250_driver_s *priv,
+ FAR uint8_t *buffer,
+ size_t buflen)
+{
+#ifdef CONFIG_LAN9250_SPI
+# if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+ uint8_t cmd_buffer[4];
+# else
+ uint8_t cmd_buffer[3];
+# endif
+
+ DEBUGASSERT(priv && priv->spi);
+ DEBUGASSERT(buflen <= sizeof(priv->pktbuf));
+
+ /* Read dummy data */
+
+ lan9250_get_reg(priv, LAN9250_RXDFR);
+
+ /* Read valid buffer data */
+
+ cmd_buffer[0] = LAN9250_SPI_READ;
+ cmd_buffer[1] = (uint8_t)(LAN9250_RXDFR >> 8);
+ cmd_buffer[2] = (uint8_t)(LAN9250_RXDFR >> 0);
+# if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+ cmd_buffer[3] = 0xff; /* SPI read dummy */
+# endif
+
+ /* Select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+ /* Send the read command and register address */
+
+ SPI_SNDBLOCK(priv->spi, cmd_buffer, sizeof(cmd_buffer));
+ SPI_RECVBLOCK(priv->spi, buffer, buflen);
+
+ /* De-select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+ struct qspi_meminfo_s meminfo;
+ int ret;
+
+ meminfo.cmd = LAN9250_SPI_READ;
+ meminfo.addr = LAN9250_RXDFR;
+ meminfo.addrlen = sizeof(uint16_t);
+ meminfo.buffer = buffer;
+ meminfo.buflen = buflen;
+ meminfo.dummies = 16; /* 8 SPI dummy clock and 4 dummy RX bytes */
+ meminfo.flags = QSPIMEM_READ;
+ if (priv->sqi_mode)
+ {
+ meminfo.flags |= QSPIMEM_IQUAD;
+ }
+
+ ret = QSPI_MEMORY(priv->qspi, &meminfo);
+ DEBUGASSERT(ret == 0);
+#endif /* CONFIG_LAN9250_SPI */
+
+ lan9250_buffer_dump(LAN9250_RXDFR, buffer, buflen);
+}
+
+/****************************************************************************
+ * Name: lan9250_send_buffer
+ *
+ * Description:
+ * Write a buffer of data.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * buffer - A pointer to the buffer to write from
+ * buflen - The number of bytes to write
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_send_buffer(FAR struct lan9250_driver_s *priv,
+ FAR const uint8_t *buffer,
+ size_t buflen)
+{
+#ifdef CONFIG_LAN9250_SPI
+ uint8_t cmd_buffer[3];
+ uint32_t regval;
+#else
+ struct qspi_meminfo_s meminfo;
+ uint32_t regval;
+ int ret;
+#endif
+
+ lan9250_buffer_dump(LAN9250_TXDFR, buffer, buflen);
+
+ /**
+ * LAN9250 SPI write command A fields:
+ *
+ * - TX packet length 4 bytes align
+ * - First frame
+ * - Last frame
+ */
+
+ regval = SPI_CMD_WRITE_A_4BA | SPI_CMD_WRITE_A_FS |
+ SPI_CMD_WRITE_A_LS | buflen;
+ lan9250_set_reg(priv, LAN9250_TXDFR, regval);
+
+ /**
+ * LAN9250 SPI write command B fields:
+ *
+ * - Packet TAG
+ */
+
+ regval = SPI_CMD_WRITE_B_PT | buflen;
+ lan9250_set_reg(priv, LAN9250_TXDFR, regval);
+
+#ifdef CONFIG_LAN9250_SPI
+
+ /* Read valid buffer data */
+
+ cmd_buffer[0] = LAN9250_SPI_WRITE;
+ cmd_buffer[1] = (uint8_t)(LAN9250_TXDFR >> 8);
+ cmd_buffer[2] = (uint8_t)(LAN9250_TXDFR >> 0);
+
+ /* Select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+ /* Send the read command and register address, total 3 bytes */
+
+ SPI_SNDBLOCK(priv->spi, cmd_buffer, 3);
+
+ /* Write data into FIFO with 4-byte align */
+
+ SPI_SNDBLOCK(priv->spi, buffer, LAN9250_ALIGN(buflen));
+
+ /* De-select LAN9250 chip */
+
+ SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+ meminfo.cmd = LAN9250_SPI_WRITE;
+ meminfo.addr = LAN9250_TXDFR;
+ meminfo.addrlen = sizeof(uint16_t);
+ meminfo.buffer = (void *)buffer;
+ meminfo.buflen = LAN9250_ALIGN(buflen);
+ meminfo.dummies = 0;
+ meminfo.flags = QSPIMEM_WRITE;
+ if (priv->sqi_mode)
+ {
+ meminfo.flags |= QSPIMEM_IQUAD;
+ }
+
+ ret = QSPI_MEMORY(priv->qspi, &meminfo);
+ DEBUGASSERT(ret == 0);
+#endif /* CONFIG_LAN9250_SPI */
+}
+
+/****************************************************************************
+ * Name: lan9250_enable_sqi
+ *
+ * Description:
+ * Send a command to LAN9250 to enable SQI mode.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_LAN9250_SQI
+static void lan9250_enable_sqi(FAR struct lan9250_driver_s *priv)
+{
+ clock_t tout_ticks = clock_systime_ticks() +
+ MSEC2TICK(LAN9250_SQI_TIMEOUT);
+ struct qspi_cmdinfo_s cmdinfo;
+ int ret;
+
+ cmdinfo.cmd = LAN9250_SPI_ENABLE_SQI;
+ cmdinfo.addrlen = 0;
+ cmdinfo.buflen = 0;
+ cmdinfo.flags = 0;
+
+ ret = QSPI_COMMAND(priv->qspi, &cmdinfo);
+ DEBUGASSERT(ret == 0);
+
+ /* USE SQI mode interface */
+
+ priv->sqi_mode = true;
+
+ /* Check read register value in SQI mode */
+
+ while (1)
+ {
+ if ((lan9250_get_reg(priv, LAN9250_BOTR) & BOTR_MASK) == BOTR_VAL)
+ {
+ break;
+ }
+ else if (clock_systime_ticks() > tout_ticks)
+ {
+ /* Check timeout and continue to use SPI mode */
+
+ priv->sqi_mode = false;
+ break;
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: lan9250_sw_reset
+ *
+ * Description:
+ * Send a command to reset LAN9250.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_sw_reset(FAR struct lan9250_driver_s *priv)
+{
+ /* Wait until LAN9250 SPI bus is ready */
+
+ lan9250_wait_ready(priv, LAN9250_BOTR, BOTR_MASK,
+ BOTR_VAL, LAN9250_RESET_TIMEOUT);
+
+ /**
+ * Send a command to reset:
+ *
+ * - Digital controller
+ * - HMAC
+ * - PHY
+ */
+
+ lan9250_set_reg(priv, LAN9250_RSTCR, RSTCR_DR | RSTCR_PHYR | RSTCR_HMACR);
+
+ /* Wait some time for hardware ready */
+
+ lan9250_wait_ready(priv, LAN9250_HWCFGR, HWCFGR_READY,
+ HWCFGR_READY, LAN9250_RESET_TIMEOUT);
+
+#ifdef CONFIG_LAN9250_SQI
+
+ /* Enable SQI mode */
+
+ lan9250_enable_sqi(priv);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_set_txavailabe
+ *
+ * Description:
+ * Enable or disable TX data FIFO available interrupt.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ * enable - true: enable this interrupt, false: disable this interrupt
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_txavailabe(FAR struct lan9250_driver_s *priv,
+ bool enable)
+{
+ uint32_t regval;
+
+ if (enable)
+ {
+ /**
+ * Configure FIFO level interrupt:
+ *
+ * - TX data available level: Ethernet maximum packet size, transform
+ * this value to be block number with 64-byte align
+ * - TX status level: 255, use maximum value so that this will not be
+ * actually used by this driver
+ * - RX status level: 0, so that RX interrupt can trigger once
+ * receiving one packet
+ */
+
+ regval = (((LAN9250_PKTBUF_SIZE + 63) / 64) << FLIR_FITXDAL_S) |
+ FLIR_FITXSL_M;
+
+ /* Mark TX data FIFO is unavailable */
+
+ priv->tx_available = false;
+ }
+ else
+ {
+ /**
+ * Configure FIFO level interrupt:
+ *
+ * - TX data available level: 255, so that no interrupt triggers
+ * - TX status level: 255, use maximum value so that this will not be
+ * actually used by this driver
+ * - RX status level: 0, so that RX interrupt can trigger once
+ * receiving one packet
+ */
+
+ regval = FLIR_FITXDAL_M | FLIR_FITXSL_M;
+
+ /* Mark TX data FIFO is available */
+
+ priv->tx_available = true;
+ }
+
+ lan9250_set_reg(priv, LAN9250_FLIR, regval);
+}
+
+/****************************************************************************
+ * Name: lan9250_reset
+ *
+ * Description:
+ * Stop, reset, re-initialize, and restart the LAN9250. This is done
+ * initially, on ifup, and after a TX timeout.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_reset(FAR struct lan9250_driver_s *priv)
+{
+ uint32_t regval;
+
+ nwarn("WARNING: Reset\n");
+
+ /* Configure SPI for the LAN9250 */
+
+ lan9250_config_spi(priv);
+
+ /* reset the LAN9250 by sending command */
+
+ lan9250_sw_reset(priv);
+
+ /* Read LAN9250 hardware ID */
+
+ regval = lan9250_get_reg(priv, LAN9250_CIARR);
+ if ((regval & CIARR_CID_M) != CIARR_CID_V)
+ {
+ nerr("ERROR: Bad Rev ID: %08x\n", regval);
+ return -ENODEV;
+ }
+
+ ninfo("Rev ID: %08x\n", regval & CIARR_CREV_M);
+
+ /**
+ * Configure TX FIFO size mode to be 8:
+ *
+ * - TX data FIFO size: 7680
+ * - RX data FIFO size: 7680
+ * - TX status FIFO size: 512
+ * - RX status FIFO size: 512
+ */
+
+ regval = HWCFGR_MBO | (8 << HWCFGR_TXFS_S);
+ lan9250_set_reg(priv, LAN9250_HWCFGR, regval);
+
+ /**
+ * Configure MAC automatic flow control:
+ *
+ * - Automatic flow control high level: 110
+ * - Automatic flow control low level: 55
+ * - Backpressure duration: 4
+ * - Flow control on any frame
+ */
+
+ regval = (110 << HMAFCCFGR_AFCHL_S) |
+ (55 << HMAFCCFGR_AFCLL_S) |
+ (4 << HMAFCCFGR_BPD_S) |
+ HMAFCCFGR_FCOAF;
+ lan9250_set_reg(priv, LAN9250_HMAFCCFGR, regval);
+
+ /**
+ * Configure host MAC flow control:
+ *
+ * - Pause time: 15
+ * - Flow control
+ */
+
+ regval = (0xf << HMACFCR_PT_S) | HMACFCR_FLE;
+ lan9250_set_macreg(priv, LAN9250_HMACFCR, regval);
+
+ /**
+ * Configure interrupt:
+ *
+ * - Interrupt De-assertion interval: 10
+ * - Interrupt output to pin
+ * - Interrupt pin active output low
+ * - Interrupt pin push-pull driver
+ */
+
+ regval = (10 << ICFGR_IDAI_S) |
+ ICFGR_IRQE | ICFGR_IRQBT;
+ lan9250_set_reg(priv, LAN9250_ICFGR, regval);
+
+ /**
+ * Configure interrupt trigger source, please refer to macro
+ * LAN9250_INT_SOURCE.
+ */
+
+ lan9250_set_reg(priv, LAN9250_IER, LAN9250_INT_SOURCE);
+
+ /* Disable TX data FIFO available interrupt */
+
+ lan9250_set_txavailabe(priv, false);
+
+ /**
+ * Configure RX:
+ *
+ * - RX DMA counter: Ethernet maximum packet size
+ * - RX data offset: 4, so that need read dummy before reading data
+ */
+
+ regval = (LAN9250_PKTBUF_SIZE << RXCFGR_RXDMAC_S) | (4 << RXCFGR_RXDO_S);
+ lan9250_set_reg(priv, LAN9250_RXCFGR, regval);
+
+ /**
+ * Configure remote power management:
+ *
+ * - Auto wakeup
+ * - Disable 1588 clock
+ * - Disable 1588 timestamp unit clock
+ * - Energy-detect
+ * - Wake on
+ * - PME pin push-pull driver
+ * - Clear wakeon
+ * - PME active high
+ * - PME pin
+ */
+
+ regval = PMCR_PMWU | PMCR_1588CLKD | PMCR_1588TSUCLKD |
+ PMCR_EDE | PMCR_WOE | PMCR_PMEBT |
+ PMCR_WOLS | PMCR_PMEP | PMCR_PMEE;
+ lan9250_set_reg(priv, LAN9250_PMCR, regval);
+
+ /**
+ * Configure PHY basic control:
+ *
+ * - Auto-Negotiation for speed(10 or 100Mbsp) and direction
+ * (half or full duplex)
+ */
+
+ lan9250_set_phyreg(priv, LAN9250_PHYBCR, PHYBCR_ANE);
+
+ /**
+ * Configure PHY auto-negotiation advertisement capability:
+ *
+ * - Asymmetric pause
+ * - Symmetric pause
+ * - 100Base-X full deplex if !CONFIG_LAN9250_HALFDUPPLEX
+ * - 100Base-X half deplex
+ * - 10Base-X full deplex if !CONFIG_LAN9250_HALFDUPPLEX
+ * - 10Base-X half deplex
+ * - Select IEEE802.3
+ */
+
+ regval = PHYANAR_AP | PHYANAR_SP | PHYANAR_100BXHD |
+ PHYANAR_10BXHD | PHYANAR_SF;
+#ifndef CONFIG_LAN9250_HALFDUPPLEX
+ regval |= PHYANAR_100BXFD | PHYANAR_10BXFD;
+#endif
+ lan9250_set_phyreg(priv, LAN9250_PHYANAR, regval);
+
+ /**
+ * Configure PHY special mode:
+ *
+ * - PHY mode = 111b, enable all capable and auto-nagotiation
+ * - PHY address = 1, default value is fixed to 1 by manufacturer
+ */
+
+ regval = PHYSMR_PM_M | 1;
+ lan9250_set_phyreg(priv, LAN9250_PHYSMR, regval);
+
+ /**
+ * Configure PHY special control or status indication:
+ *
+ * - Port auto-MDIX determined by bits 14 and 13
+ * - Auto-MDIX
+ * - Disable SQE tests
+ */
+
+ regval = PHYSCOSIR_AMDIXC | PHYSCOSIR_AMDIXE | PHYSCOSIR_SQETD;
+ lan9250_set_phyreg(priv, LAN9250_PHYSCOSIR, regval);
+
+ /**
+ * Configure PHY interrupt source:
+ *
+ * - Link up
+ * - Link down
+ */
+
+ regval = PHYIER_LU | PHYIER_LD;
+ lan9250_set_phyreg(priv, LAN9250_PHYIER, regval);
+
+ /**
+ * Configure special control or status:
+ *
+ * - Fixed to write 0000010b to reserved filed
+ */
+
+ lan9250_set_phyreg(priv, LAN9250_PHYSCOSR, PHYSCOSR_RD);
+
+ /* Clear interrupt status */
+
+ lan9250_set_reg(priv, LAN9250_ISR, UINT32_MAX);
+
+ /**
+ * Configure HMAC control:
+ *
+ * - Automaticaly strip the pad field on incoming packets
+ * - TX enable
+ * - RX enable
+ * - Full duplex mode if !CONFIG_LAN9250_HALFDUPPLEX
+ */
+
+ regval = HMACCR_APS | HMACCR_TXE | HMACCR_RXE;
+#ifndef CONFIG_LAN9250_HALFDUPPLEX
+ regval |= HMACCR_FDM;
+#endif
+ lan9250_set_macreg(priv, LAN9250_HMACCR, regval);
+
+ /** Configure TX:
+ *
+ * - TX enable
+ */
+
+ lan9250_set_reg(priv, LAN9250_TXCFGR, TXCFGR_TXE);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_macaddr
+ *
+ * Description:
+ * Set the MAC address to the configured value. This is done after ifup
+ * or after a TX timeout. Note that this means that the interface must
+ * be down before configuring the MAC addr.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_macaddr(FAR struct lan9250_driver_s *priv)
+{
+ uint32_t high_addr;
+ uint32_t low_addr;
+ FAR uint8_t *mac = priv->dev.d_mac.ether.ether_addr_octet;
+
+ high_addr = (((uint32_t)mac[5] << 8) | ((uint32_t)mac[4] << 0));
+ low_addr = (((uint32_t)mac[3] << 24) | ((uint32_t)mac[2] << 16) |
+ ((uint32_t)mac[1] << 8) | ((uint32_t)mac[0] << 0));
+
+ lan9250_set_macreg(priv, LAN9250_HMACAHR, high_addr);
+ lan9250_set_macreg(priv, LAN9250_HMACALR, low_addr);
+}
+
+/****************************************************************************
+ * Name: lan9250_transmit
+ *
+ * Description:
+ * Start hardware transmission. Called either from:
+ *
+ * - pkif interrupt when an application responds to the receipt of data
+ * by trying to send something, or
+ * - From watchdog based polling.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int lan9250_transmit(FAR struct lan9250_driver_s *priv)
+{
+ uint32_t regval;
+ uint16_t free_size;
+ uint8_t status_size;
+
+ regval = lan9250_get_reg(priv, LAN9250_TXFIR);
+ status_size = (regval & TXFIR_TXSFUS_M) >> TXFIR_TXSFUS_S;
+ free_size = regval & TXFIR_TXDFFS_M;
+
+ ninfo("availabe status size:%d, free space size:%d\n",
+ status_size, free_size);
+
+ /* Clear TX status FIFO if it is no empty by reading data */
+
+ for (int i = 0; i < status_size; i++)
+ {
+ lan9250_get_reg(priv, LAN9250_TXSFR);
+ }
+
+ if (free_size > priv->dev.d_len)
+ {
+ /* Increment statistics */
+
+ ninfo("Sending packet, pktlen: %d\n", priv->dev.d_len);
+ NETDEV_TXPACKETS(&priv->dev);
+
+ /* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */
+
+ lan9250_dump_buf("Transmit Packet", priv->dev.d_buf,
+ priv->dev.d_len);
+
+ lan9250_send_buffer(priv, priv->dev.d_buf, priv->dev.d_len);
+
+ if ((free_size - priv->dev.d_len) < LAN9250_PKTBUF_SIZE)
+ {
+ /* Enable TX data FIFO available interrupt */
+
+ lan9250_set_txavailabe(priv, true);
+
+ /**
+ * Enable the TX timeout watchdog (perhaps restarting the timer)
+ * when free data space is not enough.
+ */
+
+ wd_start(&priv->txtout_timer, LAN9250_TX_TIMEOUT,
+ lan9250_txtout_timercb, (wdparm_t)priv);
+ }
+ }
+ else
+ {
+ /* This condition is not supported. */
+
+ DEBUGASSERT(0);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_txpoll
+ *
+ * Description:
+ * The transmitter is available, check if the network has any outgoing
+ * packets ready to send. This is a callback from devif_poll().
+ * devif_poll() may be called:
+ *
+ * 1. When the preceding TX packet send is complete,
+ * 2. When the preceding TX packet send timesout and the interface is
+ * reset
+ * 3. During normal TX polling
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int lan9250_txpoll(FAR struct net_driver_s *dev)
+{
+ FAR struct lan9250_driver_s *priv =
+ (FAR struct lan9250_driver_s *)dev->d_private;
+
+ /* Send the packet */
+
+ lan9250_transmit(priv);
+
+ /* Stop the poll now if free FIFO buffer is not enough */
+
+ return priv->tx_available ? OK : -EBUSY;
+}
+
+/****************************************************************************
+ * Name: lan9250_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * dev - The reference to the driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_txavail_work(FAR void *arg)
+{
+ FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+ FAR struct net_driver_s *dev = &priv->dev;
+
+ /* Lock the network and serialize driver operations if necessary.
+ * NOTE: Serialization is only required in the case where the driver work
+ * is performed on an LP worker thread and where more than one LP worker
+ * thread has been configured.
+ */
+
+ net_lock();
+ lan9250_lock_spi(priv);
+
+ /* Ignore the notification if the interface is not yet up */
+
+ if (IFF_IS_UP(dev->d_flags))
+ {
+ /* Check if there is room in the hardware to hold another outgoing
+ * packet.
+ */
+
+ /* If so, then poll the network for new XMIT data */
+
+ devif_poll(dev, lan9250_txpoll);
+ }
+
+ /* Release lock on the SPI bus and the network */
+
+ lan9250_unlock_spi(priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Name: lan9250_phy_isr
+ *
+ * Description:
+ * Process LAN9250 PHY interrupt.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_phy_isr(FAR struct lan9250_driver_s *priv)
+{
+ uint16_t regval;
+
+ regval = lan9250_get_phyreg(priv, LAN9250_PHYISFR);
+ if (regval & PHYISFR_LU)
+ {
+ ninfo("Link up\n");
+
+ IFF_SET_UP(priv->dev.d_flags);
+ }
+ else if (regval & PHYISFR_LD)
+ {
+ ninfo("Link down\n");
+
+ IFF_CLR_UP(priv->dev.d_flags);
+ }
+}
+
+/****************************************************************************
+ * Name: lan9250_txavailable_isr
+ *
+ * Description:
+ * TX data FIFO available interrupt function.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_txavailable_isr(FAR struct lan9250_driver_s *priv)
+{
+ /* Update statistics */
+
+ NETDEV_TXDONE(&priv->dev);
+
+ /* Disable TX data FIFO available interrupt */
+
+ lan9250_set_txavailabe(priv, false);
+
+ /* If no further xmits are pending, then cancel the TX timeout */
+
+ wd_cancel(&priv->txtout_timer);
+
+ /* Then poll the network for new XMIT data */
+
+ devif_poll(&priv->dev, lan9250_txpoll);
+}
+
+/****************************************************************************
+ * Name: lan9250_netdev_rx
+ *
+ * Description:
+ * Give the newly received packet to the network.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_netdev_rx(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_NET_PKT
+ /* When packet sockets are enabled, feed the frame into the tap */
+
+ pkt_input(&priv->dev);
+#endif
+
+ /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+ if (BUF->type == HTONS(ETHTYPE_IP))
+ {
+ ninfo("IPv4 frame\n");
+ NETDEV_RXIPV4(&priv->dev);
+
+ /* Receive an IPv4 packet from the network device */
+
+ ipv4_input(&priv->dev);
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, d_len field will set to a value > 0.
+ */
+
+ if (priv->dev.d_len > 0)
+ {
+ /* And send the packet */
+
+ lan9250_transmit(priv);
+ }
+ }
+ else
+#endif /* CONFIG_NET_IPv4 */
+#ifdef CONFIG_NET_IPv6
+ if (BUF->type == HTONS(ETHTYPE_IP6))
+ {
+ ninfo("IPv6 frame\n");
+ NETDEV_RXIPV6(&priv->dev);
+
+ /* Give the IPv6 packet to the network layer */
+
+ ipv6_input(&priv->dev);
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, d_len field will set to a value > 0.
+ */
+
+ if (priv->dev.d_len > 0)
+ {
+ /* And send the packet */
+
+ lan9250_transmit(priv);
+ }
+ }
+ else
+#endif /* CONFIG_NET_IPv6 */
+#ifdef CONFIG_NET_ARP
+ if (BUF->type == HTONS(ETHTYPE_ARP))
+ {
+ ninfo("ARP packet received (%02x)\n", BUF->type);
+ NETDEV_RXARP(&priv->dev);
+
+ arp_input(&priv->dev);
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, d_len field will set to a value > 0.
+ */
+
+ if (priv->dev.d_len > 0)
+ {
+ lan9250_transmit(priv);
+ }
+ }
+ else
+#endif /* CONFIG_NET_ARP */
+ {
+ nwarn("WARNING: Unsupported packet type dropped (%02x)\n",
+ HTONS(BUF->type));
+ NETDEV_RXDROPPED(&priv->dev);
+ }
+}
+
+/****************************************************************************
+ * Name: lan9250_rxdone_isr
+ *
+ * Description:
+ * An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_rxdone_isr(FAR struct lan9250_driver_s *priv)
+{
+ uint8_t pktcnt;
+ uint16_t pktlen;
+ uint32_t regval;
+
+ /* Update statistics */
+
+ NETDEV_RXPACKETS(&priv->dev);
+
+ /* Check valiad packet count */
+
+ regval = lan9250_get_reg(priv, LAN9250_RXFIR);
+ pktcnt = (regval & RXFIR_RXSFUS_M) >> RXFIR_RXSFUS_S;
+
+ ninfo("pktcnt:%d\n", pktcnt);
+
+ while (pktcnt--)
+ {
+ /* Check valiad packet data size */
+
+ regval = lan9250_get_reg(priv, LAN9250_RXSFR);
+ pktlen = (regval & RXSFF_PL_M) >> RXSFF_PL_S;
+
+ ninfo("pktlen:%d\n", pktlen);
+
+ if (pktlen)
+ {
+ /**
+ * Copy the data from the receive buffer to priv->dev.d_buf.
+ * ERDPT should be correctly positioned from the last call to
+ * end_rdbuffer (above).
+ */
+
+ lan9250_recv_buffer(priv, priv->dev.d_buf, pktlen);
+
+ /**
+ * Save the packet length (without the 4 byte CRC)
+ * in priv->dev.d_len.
+ */
+
+ priv->dev.d_len = pktlen - 4;
+
+ lan9250_dump_buf("Received Packet", priv->dev.d_buf,
+ priv->dev.d_len);
+
+ /* Dispatch the packet to the network */
+
+ lan9250_netdev_rx(priv);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: lan9250_int_worker
+ *
+ * Description:
+ * Perform interrupt handling logic outside of the interrupt handler (on
+ * the work queue thread).
+ *
+ * Input Parameters:
+ * arg - The reference to the driver structure (case to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_int_worker(FAR void *arg)
+{
+ FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+ uint32_t regval;
+
+ DEBUGASSERT(priv);
+
+ /* Get exclusive access to both the network and the SPI bus. */
+
+ net_lock();
+ lan9250_lock_spi(priv);
+
+ /**
+ * There is no infinite loop check... if there are always pending
+ * interrupts, we are just broken.
+ */
+
+ regval = lan9250_get_reg(priv, LAN9250_ISR);
+ if ((regval & LAN9250_INT_SOURCE) != 0)
+ {
+ /* Handle interrupts according to interrupt resource bit
+ * settings.
+ */
+
+ ninfo("Interrupt status: %08x\n", regval);
+
+#if LAN9250_INT_SOURCE & IER_SW
+ if ((regval & ISR_SW) != 0)
+ {
+ ninfo("\tSoftware\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RAEDY
+ if ((regval & ISR_READY) != 0)
+ {
+ ninfo("\tDevice ready\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_1588
+ if ((regval & ISR_1588) != 0)
+ {
+ ninfo("\t1588\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_PHY
+ if ((regval & ISR_PHY) != 0)
+ {
+ ninfo("\tPHY\n");
+
+ lan9250_phy_isr(priv);
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXSTOP
+ if ((regval & ISR_TXS) != 0)
+ {
+ ninfo("\tTX stop\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXSTOP
+ if ((regval & ISR_RXS) != 0)
+ {
+ ninfo("\tRX stop\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXDFH
+ if ((regval & ISR_RXDFH) != 0)
+ {
+ ninfo("\tRX dropped frame count halfway\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXIOC
+ if ((regval & ISR_TXIOC) != 0)
+ {
+ ninfo("\tTX IOC\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXD
+ if ((regval & ISR_RXD) != 0)
+ {
+ ninfo("\tRX DMA\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_GPT
+ if ((regval & ISR_GPT) != 0)
+ {
+ ninfo("\tGP-timer\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_PME
+ if ((regval & ISR_PME) != 0)
+ {
+ ninfo("\tPower management\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXSO
+ if ((regval & ISR_TXSO) != 0)
+ {
+ ninfo("\tTX FIFO status overflow\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RWT
+ if ((regval & ISR_RWT) != 0)
+ {
+ ninfo("\tRX watchdog timeout\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXE
+ if ((regval & ISR_RXE) != 0)
+ {
+ ninfo("\tRX error\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXE
+ if ((regval & ISR_TXE) != 0)
+ {
+ ninfo("\tTX error\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_GPIO
+ if ((regval & ISR_GPIO) != 0)
+ {
+ ninfo("\tISR_GPIO event\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TDFO
+ if ((regval & ISR_TDFO) != 0)
+ {
+ ninfo("\tTX data FIFO overrun\n");
+ }
+#endif
+
+ if ((regval & ISR_TDFA) != 0)
+ {
+ ninfo("\tTX data FIFO available\n");
+
+ lan9250_txavailable_isr(priv);
+ }
+
+#if LAN9250_INT_SOURCE & IER_TSFF
+ if ((regval & ISR_TSFF) != 0)
+ {
+ ninfo("\tTX status FIFO full\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TSFL
+ if ((regval & ISR_TSFL) != 0)
+ {
+ ninfo("\tTX status FIFO level\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXDF
+ if ((regval & ISR_RXDF) != 0)
+ {
+ ninfo("\tRX dropped frame\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RSFF
+ if ((regval & ISR_RSFF) != 0)
+ {
+ ninfo("\tRX status FIFO full\n");
+ }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RSFL
+ if ((regval & ISR_RSFL) != 0)
+ {
+ ninfo("\tRX status FIFO level\n");
+
+ lan9250_rxdone_isr(priv);
+ }
+#endif
+
+ lan9250_set_reg(priv, LAN9250_ISR, regval);
+ }
+
+ /* Release lock on the SPI bus and the network */
+
+ lan9250_unlock_spi(priv);
+ net_unlock();
+
+ /**
+ * Enable ISR_GPIO interrupts after unlocking net so that application
+ * could have chance to process Ethernet packet and free iob.
+ */
+
+ priv->lower->enable(priv->lower);
+}
+
+/****************************************************************************
+ * Name: lan9250_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Input Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ * arg - Interrupt private data
+ *
+ * Returned Value:
+ * OK on success
+ *
+ ****************************************************************************/
+
+static int lan9250_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct lan9250_driver_s *priv;
+
+ DEBUGASSERT(arg != NULL);
+ priv = (FAR struct lan9250_driver_s *)arg;
+
+ /* In complex environments, we cannot do SPI transfers from the interrupt
+ * handler because semaphores are probably used to lock the SPI bus. In
+ * this case, we will defer processing to the worker thread. This is also
+ * much kinder in the use of system resources and is, therefore, probably
+ * a good thing to do in any event.
+ */
+
+ DEBUGASSERT(work_available(&priv->irq_work));
+
+ /* Notice that further ISR_GPIO interrupts are disabled until the work is
+ * actually performed. This is to prevent overrun of the worker thread.
+ * Interrupts are re-enabled in lan9250_int_worker() when the work is done.
+ */
+
+ priv->lower->disable(priv->lower);
+ return work_queue(LAN9250_WORK, &priv->irq_work, lan9250_int_worker,
+ (void *)priv, 0);
+}
+
+/****************************************************************************
+ * Name: lan9250_txtout_worker
+ *
+ * Description:
+ * Our TX watchdog timed out. This is the worker thread continuation of
+ * the watchdog timer interrupt. Reset the hardware and start again.
+ *
+ * Input Parameters:
+ * arg - The reference to the driver structure (case to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_txtout_worker(FAR void *arg)
+{
+ FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+ int ret;
+
+ nerr("ERROR: Tx timeout\n");
+ DEBUGASSERT(priv);
+
+ /* Get exclusive access to the network */
+
+ net_lock();
+
+ /* Increment statistics and dump debug info */
+
+ NETDEV_TXTIMEOUTS(&priv->dev);
+
+ /* Then reset the hardware: Take the interface down, then bring it
+ * back up
+ */
+
+ ret = lan9250_ifdown(&priv->dev);
+ DEBUGASSERT(ret == OK);
+ ret = lan9250_ifup(&priv->dev);
+ DEBUGASSERT(ret == OK);
+ UNUSED(ret);
+
+ /* Then poll the network for new XMIT data */
+
+ devif_poll(&priv->dev, lan9250_txpoll);
+
+ /* Release lock on the network */
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Name: lan9250_txtout_timercb
+ *
+ * Description:
+ * Our TX watchdog timed out. Called from the timer interrupt handler.
+ * The last TX never completed. Perform work on the worker thread.
+ *
+ * Input Parameters:
+ * arg - The argument
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lan9250_txtout_timercb(wdparm_t arg)
+{
+ FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+ int ret;
+
+ /* In complex environments, we cannot do SPI transfers from the timeout
+ * handler because semaphores are probably used to lock the SPI bus. In
+ * this case, we will defer processing to the worker thread. This is also
+ * much kinder in the use of system resources and is, therefore, probably
+ * a good thing to do in any event.
+ */
+
+ DEBUGASSERT(priv && work_available(&priv->txtout_work));
+
+ /* Notice that Tx timeout watchdog is not active so further Tx timeouts
+ * can occur until we restart the Tx timeout watchdog.
+ */
+
+ ret = work_queue(LAN9250_WORK, &priv->txtout_work,
+ lan9250_txtout_worker, priv, 0);
+ DEBUGASSERT(ret == OK);
+ UNUSED(ret);
+}
+
+/****************************************************************************
+ * Name: lan9250_ifup
+ *
+ * Description:
+ * NuttX Callback: Bring up the Ethernet interface when an IP address is
+ * provided
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_ifup(FAR struct net_driver_s *dev)
+{
+ FAR struct lan9250_driver_s *priv =
+ (FAR struct lan9250_driver_s *)dev->d_private;
+ int ret;
+#ifdef CONFIG_LAN9250_REGDEBUG
+ uint32_t mac_addr[2];
+#endif
+
+ ninfo("Bringing up: %u.%u.%u.%u\n",
+ ip4_addr1(dev->d_ipaddr), ip4_addr2(dev->d_ipaddr),
+ ip4_addr3(dev->d_ipaddr), ip4_addr4(dev->d_ipaddr));
+
+ /* Lock the SPI bus so that we have exclusive access */
+
+ lan9250_lock_spi(priv);
+
+ /* Initialize Ethernet interface, set the MAC address, and make sure that
+ * the LAN9250 is not in power save mode.
+ */
+
+ ret = lan9250_reset(priv);
+ if (ret == OK)
+ {
+ lan9250_set_macaddr(priv);
+
+ /* Enable interrupts at the LAN9250. Interrupts are still disabled
+ * at the interrupt controller.
+ */
+
+ /* Enable the receiver */
+
+ /* Mark the interface up and enable the Ethernet interrupt at the
+ * controller
+ */
+
+ priv->lower->enable(priv->lower);
+
+ /* Read MAC address here in debug mode */
+
+#ifdef CONFIG_LAN9250_REGDEBUG
+ mac_addr[0] = lan9250_get_macreg(priv, LAN9250_HMACALR);
+ mac_addr[1] = lan9250_get_macreg(priv, LAN9250_HMACAHR);
+
+ ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (uint8_t)(mac_addr[1] >> 0), (uint8_t)(mac_addr[1] >> 8),
+ (uint8_t)(mac_addr[0] >> 24), (uint8_t)(mac_addr[0] >> 16),
+ (uint8_t)(mac_addr[0] >> 8), (uint8_t)(mac_addr[0] >> 0));
+#endif
+ }
+
+ /* Un-lock the SPI bus */
+
+ lan9250_unlock_spi(priv);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: lan9250_ifdown
+ *
+ * Description:
+ * NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_ifdown(FAR struct net_driver_s *dev)
+{
+ FAR struct lan9250_driver_s *priv =
+ (FAR struct lan9250_driver_s *)dev->d_private;
+ irqstate_t flags;
+
+ ninfo("Taking down: %u.%u.%u.%u\n",
+ ip4_addr1(dev->d_ipaddr), ip4_addr2(dev->d_ipaddr),
+ ip4_addr3(dev->d_ipaddr), ip4_addr4(dev->d_ipaddr));
+
+ /* Lock the SPI bus so that we have exclusive access */
+
+ lan9250_lock_spi(priv);
+
+ /* Reset the device and leave in the power save state */
+
+ lan9250_sw_reset(priv);
+
+ /* Disable the Ethernet interrupt */
+
+ flags = enter_critical_section();
+ priv->lower->disable(priv->lower);
+
+ /* Cancel the TX timeout timers */
+
+ wd_cancel(&priv->txtout_timer);
+
+ IFF_CLR_UP(priv->dev.d_flags);
+ leave_critical_section(flags);
+
+ /* Un-lock the SPI bus */
+
+ lan9250_unlock_spi(priv);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_txavail
+ *
+ * Description:
+ * Driver callback invoked when new TX data is available. This is a
+ * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ * latency.
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_txavail(FAR struct net_driver_s *dev)
+{
+ FAR struct lan9250_driver_s *priv =
+ (FAR struct lan9250_driver_s *)dev->d_private;
+ irqstate_t flags;
+
+ /**
+ * Lock the SPI bus so that we have exclusive access for but SPI and
+ * LAN9250 SPI private data.
+ */
+
+ lan9250_lock_spi(priv);
+
+ flags = enter_critical_section();
+
+ /**
+ * Since SPI is locked, so interrupt work must not really process when
+ * CPU run here, so:
+ *
+ * - priv->tx_available = true, TX data FIFO is available and its related
+ * interrupt is disable.
+ * - priv->tx_available = false, TX data FIFO is unavailable and its
+ * related interrupt is enable, so when this interrupt triggers,
+ * function "devif_poll" will poll the network for new XMIT data.
+ */
+
+ if (IFF_IS_UP(dev->d_flags) &&
+ priv->tx_available &&
+ work_available(&priv->txpoll_work))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(LAN9250_WORK, &priv->txpoll_work,
+ lan9250_txavail_work, priv, 0);
+ }
+
+ /* Un-lock the SPI bus */
+
+ leave_critical_section(flags);
+ lan9250_unlock_spi(priv);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_addmac
+ *
+ * Description:
+ * NuttX Callback: Add the specified MAC address to the hardware multicast
+ * address filtering
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ * mac - The MAC address to be added
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int lan9250_addmac(FAR struct net_driver_s *dev,
+ FAR const uint8_t *mac)
+{
+ /* #warning "Multicast MAC support not implemented" */
+
+ return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: lan9250_rmmac
+ *
+ * Description:
+ * NuttX Callback: Remove the specified MAC address from the hardware
+ * multicast address filtering
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ * mac - The MAC address to be removed
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int lan9250_rmmac(FAR struct net_driver_s *dev,
+ FAR const uint8_t *mac)
+{
+ /* #warning "Multicast MAC support not implemented" */
+
+ return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_initialize
+ *
+ * Description:
+ * Initialize the LAN9250 Ethernet driver.
+ *
+ * Input Parameters:
+ * spi - A reference to the platform's SPI driver for the LAN9250 when
+ * enable CONFIG_LAN9250_SPI
+ * qspi - A reference to the platform's SQI driver for the LAN9250 when
+ * enable CONFIG_LAN9250_SQI
+ * lower - The MCU-specific interrupt used to control low-level MCU
+ * functions (i.e., LAN9250 GPIO interrupts).
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+int lan9250_initialize(
+#ifdef CONFIG_LAN9250_SPI
+ FAR struct spi_dev_s *spi,
+#else
+ FAR struct qspi_dev_s *qspi,
+#endif
+ FAR const struct lan9250_lower_s *lower)
+{
+ FAR struct lan9250_driver_s *priv = &g_lan9250;
+ FAR struct net_driver_s *dev = &priv->dev;
+
+ /* Initialize the driver structure */
+
+ memset(priv, 0, sizeof(struct lan9250_driver_s));
+
+ dev->d_buf = (uint8_t *)priv->pktbuf;
+ dev->d_ifup = lan9250_ifup;
+ dev->d_ifdown = lan9250_ifdown;
+ dev->d_txavail = lan9250_txavail;
+#ifdef CONFIG_NET_MCASTGROUP
+ dev->d_addmac = lan9250_addmac;
+ dev->d_rmmac = lan9250_rmmac;
+#endif
+ dev->d_private = priv;
+
+#ifdef CONFIG_LAN9250_SPI
+ priv->spi = spi;
+#else
+ priv->qspi = qspi;
+#endif
+
+ priv->lower = lower;
+
+ /* Attach the interrupt to the driver (but don't enable it yet) */
+
+ if (lower->attach(lower, lan9250_interrupt, priv) < 0)
+ {
+ /* We could not attach the ISR to the interrupt */
+
+ return -EAGAIN;
+ }
+
+ /* Try to read MAC address from low-level function. */
+
+ if (lower->getmac)
+ {
+ lower->getmac(lower, priv->dev.d_mac.ether.ether_addr_octet);
+ }
+
+ /* Register the device with the OS so that socket IOCTLs can be performed */
+
+ return netdev_register(dev, NET_LL_ETHERNET);
+}
diff --git a/drivers/net/lan9250.h b/drivers/net/lan9250.h
new file mode 100644
index 0000000000..6eff7e758e
--- /dev/null
+++ b/drivers/net/lan9250.h
@@ -0,0 +1,628 @@
+/****************************************************************************
+ * drivers/net/lan9250.h
+ *
+ * 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_LAN9250_H
+#define __DRIVERS_NET_LAN9250_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* LAN9250 SPI Commands *****************************************************/
+
+#define LAN9250_SPI_CMD_READ 0x03
+#define LAN9250_SPI_CMD_FREAD 0x0b
+#define LAN9250_SPI_CMD_WRITE 0x02
+#define LAN9250_SPI_CMD_ENABLE_SQI 0x38
+
+#define LAN9250_QSPI_CMD_READ 0xeb
+#define LAN9250_QSPI_CMD_WRITE 0xe2
+
+/* System Control and Status Registers **************************************/
+
+#define LAN9250_RXDFR 0x000
+#define LAN9250_TXDFR 0x020
+#define LAN9250_RXSFR 0x040
+#define LAN9250_RXSPR 0x044
+#define LAN9250_TXSFR 0x048
+#define LAN9250_TXSPR 0x04c
+#define LAN9250_CIARR 0x050
+#define LAN9250_ICFGR 0x054
+#define LAN9250_ISR 0x058
+#define LAN9250_IER 0x05c
+#define LAN9250_BOTR 0x064
+#define LAN9250_FLIR 0x068
+#define LAN9250_RXCFGR 0x06c
+#define LAN9250_TXCFGR 0x070
+#define LAN9250_HWCFGR 0x074
+#define LAN9250_RDCR 0x078
+#define LAN9250_RXFIR 0x07c
+#define LAN9250_TXFIR 0x080
+#define LAN9250_PMCR 0x084
+#define LAN9250_GPTCFGR 0x08c
+#define LAN9250_GPTCR 0x090
+#define LAN9250_FR25MCR 0x09c
+#define LAN9250_HMRDFCR 0x0a0
+#define LAN9250_HMCSRICR 0x0a4
+#define LAN9250_HMCSRIDR 0x0a8
+#define LAN9250_HMAFCCFGR 0x0ac
+#define LAN9250_HMRXLPITXR 0x0b0
+#define LAN9250_HMRXLPITR 0x0b4
+#define LAN9250_HMTXLPITXR 0x0b8
+#define LAN9250_HMTXLPITR 0x0bc
+
+/* 1588 Register Addresses */
+
+#define LAN9250_1588CACR 0x100
+#define LAN9250_1588GCFGR 0x104
+#define LAN9250_1588ISR 0x108
+#define LAN9250_1588IER 0x10c
+#define LAN9250_1588CLKSR 0x110
+#define LAN9250_1588CLKNSR 0x114
+#define LAN9250_1588CLKSNSR 0x118
+#define LAN9250_1588CLKRAR 0x11c
+#define LAN9250_1588CLKTRAR 0x120
+#define LAN9250_1588CLKTRDR 0x124
+#define LAN9250_1588CLKSAR 0x128
+#define LAN9250_1588CLKATXSR 0x12c
+#define LAN9250_1588CLKATXNSR 0x130
+#define LAN9250_1588CLKATXRASR 0x134
+#define LAN9250_1588CLKATXRANSR 0x138
+#define LAN9250_1588CLKBTXSR 0x13c
+#define LAN9250_1588CLKBTXNSR 0x140
+#define LAN9250_1588CLKBTXRASR 0x144
+#define LAN9250_1588CLKBTXRANSR 0x148
+#define LAN9250_1588UMAHWR 0x14c
+#define LAN9250_1588UMALWR 0x150
+#define LAN9250_1588BPGSR 0x154
+
+/* Bank 0 Control Register Addresses */
+
+#define LAN9250_1588PLR 0x158
+#define LAN9250_1588PAAPDR 0x15c
+#define LAN9250_1588PCIR 0x160
+
+/* Bank 1 Control Register Addresses */
+
+#define LAN9250_1588PRXPCR 0x158
+#define LAN9250_1588PRXTSCR 0x15c
+#define LAN9250_1588PRXTICR 0x160
+#define LAN9250_1588PRXFCFGR 0x168
+#define LAN9250_1588PRXITSR 0x16c
+#define LAN9250_1588PRXITNSR 0x170
+#define LAN9250_1588PRXMHR 0x174
+#define LAN9250_1588PRXPDRITSR 0x178
+#define LAN9250_1588PRXPDRITNSR 0x17c
+#define LAN9250_1588PRXPDRICFHR 0x180
+#define LAN9250_1588PRXPDRICFLR 0x184
+#define LAN9250_1588PRXCSDCR 0x188
+#define LAN9250_1588PRXFCR 0x18c
+
+/* Bank 2 Control Register Addresses */
+
+#define LAN9250_1588PTXPCR 0x158
+#define LAN9250_1588PTXTSCR 0x15c
+#define LAN9250_1588PTXMR 0x164
+#define LAN9250_1588PTXM2R 0x168
+#define LAN9250_1588PTXETSR 0x16c
+#define LAN9250_1588PTXETNSR 0x170
+#define LAN9250_1588PTXMHR 0x174
+#define LAN9250_1588PTXDRDTSR 0x178
+#define LAN9250_1588PTXDRDTNSR 0x17c
+#define LAN9250_1588TXOSSUSR 0x180
+
+/* Bank 3 Control Register Addresses */
+
+#define LAN9250_1588GPIOCCFGR 0x15c
+#define LAN9250_1588GPIOXRECLKSCR 0x16c
+#define LAN9250_1588GPIOXRECLKNSCR 0x170
+#define LAN9250_1588GPIOXFECLKSCR 0x178
+#define LAN9250_1588GPIOXFECLKNSCR 0x17c
+
+/* ISR_GPIO Register Addresses */
+
+#define LAN9250_GPIOCFGR 0x1e0
+#define LAN9250_GPIODADR 0X1e4
+#define LAN9250_GPIOISAER 0X1e8
+
+/* Reset Register Addresses */
+
+#define LAN9250_RSTCR 0x1f8
+
+/* Host MAC Registers *******************************************************/
+
+#define LAN9250_HMACCR 0x01
+#define LAN9250_HMACAHR 0x02
+#define LAN9250_HMACALR 0x03
+#define LAN9250_HMACHTHR 0x04
+#define LAN9250_HMACHTLR 0x05
+#define LAN9250_HMACMIIAR 0x06
+#define LAN9250_HMACMIIDR 0x07
+#define LAN9250_HMACFCR 0x08
+#define LAN9250_HMACVLAN1TR 0x09
+#define LAN9250_HMACVLAN2TR 0x0a
+#define LAN9250_HMACWUFFR 0x0b
+#define LAN9250_HMACWUCASR 0x0c
+#define LAN9250_HMACCSOECR 0x0d
+#define LAN9250_HMACEEETWTXSR 0x0e
+#define LAN9250_HMACEEETXLPIRDR 0x0f
+
+/* PHY Registers ************************************************************/
+
+#define LAN9250_PHYBCR 0
+#define LAN9250_PHYBSR 1
+#define LAN9250_PHYIMSBR 2
+#define LAN9250_PHYILSBR 3
+#define LAN9250_PHYANAR 4
+#define LAN9250_PHYANLPBPAR 5
+#define LAN9250_PHYANER 6
+#define LAN9250_PHYANNPTXR 7
+#define LAN9250_PHYANNPRXR 8
+#define LAN9250_PHYMMDACR 13
+#define LAN9250_PHYMMDAODR 14
+#define LAN9250_PHYEDPDCFGR 16
+#define LAN9250_PHYMCOSR 17
+#define LAN9250_PHYSMR 18
+#define LAN9250_PHYTDRPODCR 24
+#define LAN9250_PHYTDRCOSR 25
+#define LAN9250_PHYSECR 26
+#define LAN9250_PHYSCOSIR 27
+#define LAN9250_PHYCLR 28
+#define LAN9250_PHYISFR 29
+#define LAN9250_PHYIER 30
+#define LAN9250_PHYSCOSR 31
+
+/* LAN9250 SPI Commands Fields **********************************************/
+
+/* SPI Write Command A */
+
+#define SPI_CMD_WRITE_A_IOC 0X80000000
+#define SPI_CMD_WRITE_A_BEA 0x03000000
+#define SPI_CMD_WRITE_A_4BA 0x00000000
+#define SPI_CMD_WRITE_A_16BA 0x01000000
+#define SPI_CMD_WRITE_A_32BA 0x02000000
+#define SPI_CMD_WRITE_A_DO 0x00000000
+#define SPI_CMD_WRITE_A_FS 0x00002000
+#define SPI_CMD_WRITE_A_LS 0x00001000
+#define SPI_CMD_WRITE_A_BS_M 0x000007ff
+
+/* SPI Write Command B */
+
+#define SPI_CMD_WRITE_B_PT 0x05200000
+#define SPI_CMD_WRITE_B_CE 0x00004000
+#define SPI_CMD_WRITE_B_ACD 0x00002000
+#define SPI_CMD_WRITE_B_DP 0x00001000
+#define SPI_CMD_WRITE_B_PL_M 0x000007ff
+
+/* RX FIFO Status Format Fields *********************************************/
+
+#define RXSFF_PF 0x80000000
+#define RXSFF_FF 0x40000000
+#define RXSFF_PL_M 0x3fff0000
+#define RXSFF_PL_S 16
+#define RXSFF_ES 0x00008000
+#define RXSFF_BF 0x00002000
+#define RXSFF_LE 0x00001000
+#define RXSFF_RF 0x00000800
+#define RXSFF_MF 0x00000400
+#define RXSFF_FTL 0x00000080
+#define RXSFF_CS 0x00000040
+#define RXSFF_FT 0x00000020
+#define RXSFF_RWTO 0x00000010
+#define RXSFF_MIIE 0x00000008
+#define RXSFF_DB 0x00000004
+#define RXSFF_CRCE 0x00000002
+
+/* System Control and Status Registers Fields *******************************/
+
+/* RX FIFO Status Register */
+
+#define RXFIR_RXSFUS_M 0x00ff0000
+#define RXFIR_RXSFUS_S 16
+#define RXFIR_RXDFUS_M 0x0000ffff
+
+/* TX FIFO Status Register */
+
+#define TXFIR_TXSFUS_M 0x00ff0000
+#define TXFIR_TXSFUS_S 16
+#define TXFIR_TXDFFS_M 0x0000ffff
+
+/* Hardware Configuration Register */
+
+#define HWCFGR_READY 0x08000000
+#define HWCFGR_AMDIXENSS 0x02000000
+#define HWCFGR_MBO 0x00100000
+#define HWCFGR_TXFS_M 0x000f0000
+#define HWCFGR_TXFS_S 16
+
+/* Byte Order Test Register */
+
+#define BOTR_MASK 0xffffffff
+#define BOTR_VAL 0x87654321
+
+/* Host MAC Automatic Flow Control Configuration Register */
+
+#define HMAFCCFGR_AFCHL_M 0x00ff0000
+#define HMAFCCFGR_AFCHL_S 16
+#define HMAFCCFGR_AFCLL_M 0x0000ff00
+#define HMAFCCFGR_AFCLL_S 8
+#define HMAFCCFGR_BPD_M 0x000000f0
+#define HMAFCCFGR_BPD_S 4
+#define HMAFCCFGR_FCOMF 0x00000008
+#define HMAFCCFGR_FCOBF 0x00000004
+#define HMAFCCFGR_FCOAD 0x00000002
+#define HMAFCCFGR_FCOAF 0x00000001
+
+/* Chip ID and Revision Register */
+
+#define CIARR_CID_M 0xffff0000
+#define CIARR_CID_S 16
+#define CIARR_CID_V (0x9250 << 16)
+#define CIARR_CREV_M 0x0000ffff
+
+/* Interrupt Configuration Register */
+
+#define ICFGR_IDAI_M 0xf0000000
+#define ICFGR_IDAI_S 24
+#define ICFGR_IDAIC 0x00004000
+#define ICFGR_IDAS 0x00002000
+#define ICFGR_MI 0x00001000
+#define ICFGR_IRQE 0x00000100
+#define ICFGR_IRQP 0x00000010
+#define ICFGR_IRQCLKS 0x00000002
+#define ICFGR_IRQBT 0x00000001
+
+/* Interrupt Enable Register */
+
+#define IER_SW 0x80000000
+#define IER_RAEDY 0x40000000
+#define IER_1588 0x20000000
+#define IER_PHY 0x04000000
+#define IER_TXSTOP 0x02000000
+#define IER_RXSTOP 0x01000000
+#define IER_RXDFH 0x00800000
+#define IER_TXIOC 0x00200000
+#define IER_RXD 0x00100000
+#define IER_GPT 0x00080000
+#define IER_PME 0x00020000
+#define IER_TXSO 0x00010000
+#define IER_RWT 0x00008000
+#define IER_RXE 0x00004000
+#define IER_TXE 0x00002000
+#define IER_GPIO 0x00001000
+#define IER_TDFO 0x00000400
+#define IER_TDFA 0x00000200
+#define IER_TSFF 0x00000100
+#define IER_TSFL 0x00000080
+#define IER_RXDF 0x00000040
+#define IER_RSFF 0x00000010
+#define IER_RSFL 0x00000008
+
+/* Interrupt Status Register */
+
+#define ISR_SW 0x80000000
+#define ISR_READY 0x40000000
+#define ISR_1588 0x20000000
+#define ISR_PHY 0x04000000
+#define ISR_TXS 0x02000000
+#define ISR_RXS 0x01000000
+#define ISR_RXDFH 0x00800000
+#define ISR_TXIOC 0x00200000
+#define ISR_RXD 0x00100000
+#define ISR_GPT 0x00080000
+#define ISR_PME 0x00020000
+#define ISR_TXSO 0x00010000
+#define ISR_RWT 0x00008000
+#define ISR_RXE 0x00004000
+#define ISR_TXE 0x00002000
+#define ISR_GPIO 0x00001000
+#define ISR_TDFO 0x00000400
+#define ISR_TDFA 0x00000200
+#define ISR_TSFF 0x00000100
+#define ISR_TSFL 0x00000080
+#define ISR_RXDF 0x00000040
+#define ISR_RSFF 0x00000010
+#define ISR_RSFL 0x00000008
+
+/* FIFO Level Interrupt Register */
+
+#define FLIR_FITXDAL_M 0xff000000
+#define FLIR_FITXDAL_S 24
+#define FLIR_FITXSL_M 0x00ff0000
+#define FLIR_FITXSL_S 16
+#define FLIR_FIRXSL_M 0x000000ff
+#define FLIR_FIRXSL_S 0
+
+/* Receive Configuration Register */
+
+#define RXCFGR_RXEA 0xc0000000
+#define RXCFGR_RXDMAC 0x06000000
+#define RXCFGR_RXDMAC_M 0x0fff0000
+#define RXCFGR_RXDMAC_S 16
+#define RXCFGR_FRXD 0x00008000
+#define RXCFGR_RXDO_M 0x00001f00
+#define RXCFGR_RXDO_S 8
+
+/* Transmit Configuration Register */
+
+#define TXCFGR_FTXSD 0x00008000
+#define TXCFGR_FTXDD 0x00004000
+#define TXCFGR_TXSAO 0x00000004
+#define TXCFGR_TXE 0x00000002
+#define TXCFGR_TXD 0x00000001
+
+/* Power Management Control Register */
+
+#define PMCR_PMM_M 0xe0000000
+#define PMCR_PMSE 0x10000000
+#define PMCR_PMWU 0x08000000
+#define PMCR_LEDD 0x04000000
+#define PMCR_1588CLKD 0x02000000
+#define PMCR_1588TSUCLKD 0x00400000
+#define PMCR_HMACCLKD 0x00080000
+#define PMCR_HMACSCOD 0x00040000
+#define PMCR_EDS 0x00010000
+#define PMCR_EDE 0x00004000
+#define PMCR_WOE 0x00000200
+#define PMCR_PMEBT 0x00000040
+#define PMCR_WOLS 0x00000020
+#define PMCR_PMEI 0x00000008
+#define PMCR_PMEP 0x00000004
+#define PMCR_PMEE 0x00000002
+#define PMCR_READY 0x00000001
+
+/* Host MAC CSR Interface Command Register */
+
+#define HMCSRICR_CSRB 0x80000000
+#define HMCSRICR_RNW 0x40000000
+#define HMCSRICR_CSRA_M 0x000000ff
+
+/* Reset Control Register */
+
+#define RSTCR_HMACR 0x00000020
+#define RSTCR_PHYR 0x00000002
+#define RSTCR_DR 0x00000001
+
+/* Host MAC Registers Fields ************************************************/
+
+/* Host MAC Control Register */
+
+#define HMACCR_RXAM 0x80000000
+#define HMACCR_EEEE 0x02000000
+#define HMACCR_DRXO 0x00400000
+#define HMACCR_LOM 0x00200000
+#define HMACCR_FDM 0x00100000
+#define HMACCR_PAM 0x00080000
+#define HMACCR_PM 0x00040000
+#define HMACCR_IF 0x00020000
+#define HMACCR_PBF 0x00010000
+#define HMACCR_HOFM 0x00008000
+#define HMACCR_HOPFM 0x00002000
+#define HMACCR_DBF 0x00000800
+#define HMACCR_DR 0x00000400
+#define HMACCR_APS 0x00000100
+#define HMACCR_BOL_M 0x000000c0
+#define HMACCR_DC 0x00000020
+#define HMACCR_TXE 0x00000008
+#define HMACCR_RXE 0x00000004
+
+/* Host MAC MII Access Register */
+
+#define HMACMIIAR_PHYA_M 0x0000f800
+#define HMACMIIAR_PHYA_S 11
+#define HMACMIIAR_MIIRX_M 0x000007c0
+#define HMACMIIAR_MIIRX_S 6
+#define HMACMIIAR_MIIW 0x00000002
+#define HMACMIIAR_MIIB 0x00000001
+
+/* Host MAC Flow Control Register */
+
+#define HMACFCR_PT_M 0xffff0000
+#define HMACFCR_PT_S 16
+#define HMACFCR_PCF 0x00000004
+#define HMACFCR_FLE 0x00000002
+#define HMACFCR_FLB 0x00000001
+
+/* PHY Registers Fields *****************************************************/
+
+/* PHY Basic Control Register */
+
+#define PHYBCR_SWR 0x8000
+#define PHYBCR_LB 0x4000
+#define PHYBCR_SSLSB 0x2000
+#define PHYBCR_ANE 0x1000
+#define PHYBCR_PD 0x0800
+#define PHYBCR_RAN 0x0200
+#define PHYBCR_DM 0x0100
+#define PHYBCR_CTM 0x0080
+
+/* PHY Basic Status Register */
+
+#define PHYBSR_100BT4 0x8000
+#define PHYBSR_100BXFD 0x4000
+#define PHYBSR_100BXHD 0x2000
+#define PHYBSR_10BXFD 0x1000
+#define PHYBSR_10BXHD 0x0800
+#define PHYBSR_100BT2FD 0x0400
+#define PHYBSR_100BT2HD 0x0200
+#define PHYBSR_ES 0x0100
+#define PHYBSR_UDA 0x0080
+#define PHYBSR_MFPS 0x0040
+#define PHYBSR_ANC 0x0020
+#define PHYBSR_RF 0x0010
+#define PHYBSR_ANA 0x0008
+#define PHYBSR_LS 0x0004
+#define PHYBSR_JD 0x0002
+#define PHYBSR_EC 0x0001
+
+/* PHY Identification MSB Register */
+
+#define PHYIMSBR_ID 0xffff
+
+/* PHY Identification LSB Register */
+
+#define PHYILSBR_ID_M 0xfc00
+#define PHYILSBR_ID_S 10
+#define PHYILSBR_MN_M 0x03f0
+#define PHYILSBR_MN_S 4
+#define PHYILSBR_RN_M 0x000f
+#define PHYILSBR_RN_S 0
+
+/* PHY Auto-Negotiation Advertisement Register */
+
+#define PHYANAR_NP 0x8000
+#define PHYANAR_RF 0x2000
+#define PHYANAR_ENP 0x1000
+#define PHYANAR_AP 0x0800
+#define PHYANAR_SP 0x0400
+#define PHYANAR_100BXFD 0x0100
+#define PHYANAR_100BXHD 0x0080
+#define PHYANAR_10BXFD 0x0040
+#define PHYANAR_10BXHD 0x0020
+#define PHYANAR_SF 0x0001
+
+/* PHY Auto-Negotiation Link Partner Base Page Ability Register */
+
+#define PHYANLPBPAR_NP 0x8000
+#define PHYANLPBPAR_ACK 0x4000
+#define PHYANLPBPAR_RF 0x2000
+#define PHYANLPBPAR_ENP 0x1000
+#define PHYANLPBPAR_AP 0x0800
+#define PHYANLPBPAR_PAUSE 0x0400
+#define PHYANLPBPAR_100BT4 0x0200
+#define PHYANLPBPAR_100BXFD 0x0100
+#define PHYANLPBPAR_100BXHD 0x0080
+#define PHYANLPBPAR_10BXFD 0x0040
+#define PHYANLPBPAR_10BXHD 0x0020
+#define PHYANLPBPAR_SF_M 0x001f
+
+/* PHY Auto-Negotiation Expansion Register */
+
+#define PHYANER_RXNPLA 0x0040
+#define PHYANER_RXNPSL 0x0020
+#define PHYANER_PDF 0x0010
+#define PHYANER_LPNPA 0x0008
+#define PHYANER_NPA 0x0004
+#define PHYANER_PRX 0x0002
+#define PHYANER_LPANA 0x0001
+
+/* PHY Auto-Negotiation Next Page TX Register */
+
+#define PHYANNPTXR_NP 0x8000
+#define PHYANNPTXR_MP 0x2000
+#define PHYANNPTXR_ACK2 0x1000
+#define PHYANNPTXR_TOG 0x0800
+#define PHYANNPTXR_MC_M 0x07ff
+
+/* PHY Auto-Negotiation Next Page RX Register */
+
+#define PHYANNPRXR_NP 0x8000
+#define PHYANNPRXR_ACK 0x4000
+#define PHYANNPRXR_MP 0x2000
+#define PHYANNPRXR_ACK2 0x1000
+#define PHYANNPRXR_TOG 0x0800
+#define PHYANNPRXR_MC_M 0x07ff
+
+/* PHY MMD Access Control Register */
+
+#define PHYMMDACR_MMDF_M 0xc000
+#define PHYMMDACR_MMDDA_M 0x001f
+
+/* PHY EDPD NLP/Crossover Time/EEE Configuration Register */
+
+#define PHYEDPDCFGR_EDPDTXNLPE 0x8000
+#define PHYEDPDCFGR_EDPDTXNLPITS_M 0x6000
+#define PHYEDPDCFGR_EDPDRXSNLPWE 0x1000
+#define PHYEDPDCFGR_EDPDRXNLPMIDS_M 0x0c00
+#define PHYEDPDCFGR_PEEEE 0x0004
+#define PHYEDPDCFGR_EDPDEC 0x0002
+#define PHYEDPDCFGR_EMAMDIXCT 0x0001
+
+/* PHY Mode Control/Status Register */
+
+#define PHYMCOSR_EDPD 0x2000
+#define PHYMCOSR_AIM 0x0040
+#define PHYMCOSR_EO 0x0002
+
+/* PHY Special Modes Register */
+
+#define PHYSMR_100BFXM 0x0400
+#define PHYSMR_PM_M 0x00e0
+#define PHYSMR_PM_S 5
+#define PHYSMR_ADDR_M 0x001f
+#define PHYSMR_ADDR_S 0x00e0
+
+/* PHY TDR Patterns/Delay Control Register */
+
+#define PHYTDRCOSR_TDRDI 0x8000
+#define PHYTDRCOSR_TDRLBC_M 0x7000
+#define PHYTDRCOSR_TDRPH 0x0fc0
+#define PHYTDRCOSR_TDRPL 0x003f
+
+/* PHY TDR Control/Status Register */
+
+#define PHYTDRCOSR_TDRE 0x8000
+#define PHYTDRCOSR_TDRATDFE 0x4000
+#define PHYTDRCOSR_TDRCCT 0x0600
+#define PHYTDRCOSR_TDRCS 0x0100
+#define PHYTDRCOSR_TDRCL 0x00FF
+
+/* PHY Special Control/Status Indication register */
+
+#define PHYSCOSIR_AMDIXC 0x8000
+#define PHYSCOSIR_AMDIXE 0x4000
+#define PHYSCOSIR_DMDIXS 0x2000
+#define PHYSCOSIR_SQETD 0x0800
+#define PHYSCOSIR_FEFIE 0x0020
+#define PHYSCOSIR_10BTPS 0x0010
+
+/* PHY Cable Length Register */
+
+#define PHYCLR_CL_M 0xf000
+
+/* PHY Interrupt Source Flags Register */
+
+#define PHYISFR_LU 0x0200
+#define PHYISFR_EO 0x0080
+#define PHYISFR_ANC 0x0040
+#define PHYISFR_RF 0x0020
+#define PHYISFR_LD 0x0010
+#define PHYISFR_ANLPA 0x0008
+#define PHYISFR_PDF 0x0004
+#define PHYISFR_ANPR 0x0002
+
+/* PHY Interrupt Enable Register */
+
+#define PHYIER_LU 0x0200
+#define PHYIER_EO 0x0080
+#define PHYIER_ANC 0x0040
+#define PHYIER_RF 0x0020
+#define PHYIER_LD 0x0010
+#define PHYIER_ANLPA 0x0008
+#define PHYIER_PDF 0x0004
+#define PHYIER_ANPR 0x0002
+
+/* PHY Special Control/Status Register */
+
+#define PHYSCOSR_AD 0x8000
+#define PHYSCOSR_RD 0x0040
+#define PHYSCOSR_SI_M 0x001c
+
+#endif /* __DRIVERS_NET_LAN9250_H */
diff --git a/include/nuttx/net/lan9250.h b/include/nuttx/net/lan9250.h
new file mode 100644
index 0000000000..5702212102
--- /dev/null
+++ b/include/nuttx/net/lan9250.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+ * include/nuttx/net/lan9250.h
+ *
+ * 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_LAN9250_H
+#define __INCLUDE_NUTTX_NET_LAN9250_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The LAN9250 device typically provides interrupts to the MCU through a GPIO
+ * pin. The structure below provides an MCU-independent mechanism for
+ * controlling this LAN9250 GPIO interrupt.
+ *
+ * "When an enabled interrupt occurs, the interrupt pin will remain low until
+ * all flags which are causing the interrupt are cleared or masked off
+ * (enable bit is cleared) by the host controller." However, the interrupt
+ * will behave like a falling edge interrupt because "After an interrupt
+ * occurs, the host controller [clears] the global enable bit for the
+ * interrupt pin before servicing the interrupt. Clearing the enable bit
+ * will cause the interrupt pin to return to the non-asserted state (high).
+ * Doing so will prevent the host controller from missing a falling edge
+ * should another interrupt occur while the immediate interrupt is being
+ * serviced."
+ */
+
+struct lan9250_lower_s
+{
+ int (*attach)(FAR const struct lan9250_lower_s *lower, xcpt_t handler,
+ FAR void *arg);
+ void (*enable)(FAR const struct lan9250_lower_s *lower);
+ void (*disable)(FAR const struct lan9250_lower_s *lower);
+
+ /* This function is optional and used to get a specific MAC address from
+ * a MCU-specific implementation. If this function is NULL, the LAN9250
+ * driver will not read the MAC from the CPU.
+ */
+
+ void (*getmac)(FAR const struct lan9250_lower_s *lower, FAR uint8_t *mac);
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_initialize
+ *
+ * Description:
+ * Initialize the LAN9250 Ethernet driver.
+ *
+ * Input Parameters:
+ * spi - A reference to the platform's SPI driver for the LAN9250 when
+ * enable CONFIG_LAN9250_SPI
+ * qspi - A reference to the platform's SQI driver for the LAN9250 when
+ * enable CONFIG_LAN9250_SQI
+ * lower - The MCU-specific interrupt used to control low-level MCU
+ * functions (i.e., LAN9250 GPIO interrupts).
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_LAN9250_SPI
+struct spi_dev_s; /* see nuttx/spi/spi.h */
+#else
+struct qspi_dev_s; /* see nuttx/spi/qspi.h */
+#endif
+int lan9250_initialize(
+#ifdef CONFIG_LAN9250_SPI
+ FAR struct spi_dev_s *spi,
+#else
+ FAR struct qspi_dev_s *qspi,
+#endif
+ FAR const struct lan9250_lower_s *lower);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_LAN9250_H */