diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index bb270190aab..7c578538022 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -73,6 +73,7 @@ config IMXRT_ENET bool "Ethernet" default n select ARCH_HAVE_PHY + select ARCH_PHY_INTERRUPT select ARCH_HAVE_NETDEV_STATISTICS menu "FlexIO Peripherals" diff --git a/arch/arm/src/imxrt/imxrt_enet.c b/arch/arm/src/imxrt/imxrt_enet.c index 3ade9f7b519..bee5352ff9f 100644 --- a/arch/arm/src/imxrt/imxrt_enet.c +++ b/arch/arm/src/imxrt/imxrt_enet.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #ifdef CONFIG_NET_PKT @@ -334,6 +335,9 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, /* PHY/MII support */ +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int imxrt_phyintenable(struct imxrt_driver_s *priv); +#endif static inline void imxrt_initmii(struct imxrt_driver_s *priv); static int imxrt_writemii(struct imxrt_driver_s *priv, uint8_t phyaddr, uint8_t regaddr, uint16_t data); @@ -644,9 +648,9 @@ static inline void imxrt_dispatch(FAR struct imxrt_driver_s *priv) pkt_input(&priv->dev); #endif - /* We only accept IP packets of the configured type and ARP packets */ - #ifdef CONFIG_NET_IPv4 + /* Check for an IPv4 packet */ + if (BUF->type == HTONS(ETHTYPE_IP)) { ninfo("IPv4 frame\n"); @@ -688,6 +692,8 @@ static inline void imxrt_dispatch(FAR struct imxrt_driver_s *priv) else #endif #ifdef CONFIG_NET_IPv6 + /* Check for an IPv6 packet */ + if (BUF->type == HTONS(ETHTYPE_IP6)) { ninfo("Iv6 frame\n"); @@ -726,6 +732,8 @@ static inline void imxrt_dispatch(FAR struct imxrt_driver_s *priv) else #endif #ifdef CONFIG_NET_ARP + /* Check for an ARP packet */ + if (BUF->type == htons(ETHTYPE_ARP)) { NETDEV_RXARP(&priv->dev); @@ -1544,6 +1552,22 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) switch (cmd) { #ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ + { + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); + + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = imxrt_phyintenable(priv); + } + } + break; +#endif + case SIOCGMIIPHY: /* Get MII PHY address */ { struct mii_ioctl_data_s *req = @@ -1568,7 +1592,7 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) ret = imxrt_writemii(priv, req->phy_id, req->reg_num, req->val_in); } break; -#endif /* ifdef CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_PHY_IOCTL */ default: ret = -ENOTTY; @@ -1579,6 +1603,54 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) } #endif /* CONFIG_NETDEV_IOCTL */ +/**************************************************************************** + * Function: imxrt_phyintenable + * + * Description: + * Enable link up/down PHY interrupts. The interrupt protocol is like this: + * + * - Interrupt status is cleared when the interrupt is enabled. + * - Interrupt occurs. Interrupt is disabled (at the processor level) when + * is received. + * - Interrupt status is cleared when the interrupt is re-enabled. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno (-ETIMEDOUT) on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int imxrt_phyintenable(struct imxrt_driver_s *priv) +{ +#if defined(CONFIG_ETH0_PHY_KSZ8051) || defined(CONFIG_ETH0_PHY_KSZ8061) || \ + defined(CONFIG_ETH0_PHY_KSZ8081) + uint16_t phyval; + int ret; + + /* Read the interrupt status register in order to clear any pending + * interrupts + */ + + ret = imxrt_readmii(priv, priv->phyaddr, MII_KSZ8081_INT, &phyval); + if (ret == OK) + { + /* Enable link up/down interrupts */ + + ret = imxrt_writemii(priv, priv->phyaddr, MII_KSZ8081_INT, + (MII_KSZ80x1_INT_LDEN | MII_KSZ80x1_INT_LUEN)); + } + + return ret; +#else +# error Unrecognized PHY + return -ENOSYS; +#endif +} +#endif + /**************************************************************************** * Function: imxrt_initmii * @@ -2238,7 +2310,6 @@ int imxrt_netinitialize(int intf) mac[3] = (uidl & 0x00ff0000) >> 16; mac[4] = (uidl & 0x0000ff00) >> 8; mac[5] = (uidl & 0x000000ff); - #endif #ifdef CONFIG_IMXRT_ENET_PHYINIT diff --git a/configs/imxrt1050-evk/README.txt b/configs/imxrt1050-evk/README.txt index 5193b1c9fda..a663594a045 100644 --- a/configs/imxrt1050-evk/README.txt +++ b/configs/imxrt1050-evk/README.txt @@ -186,6 +186,31 @@ Configuration sub-directories Or, disable IPv4 support so that only IPv4 addressing is used. + 3. The network monitor is not enabled in this configuration. As a + result, the Ethernet cable must be connected when the board is + powered up. Otherwise, it will stall for a long period of time + before the NSH prompt appears and you will not be able to used + the board. + + The following configuration options should be added to your + configuration in order to use the network monitor: + + CONFIG_IMXRT_ENET_PHYINIT=y + CONFIG_IMXRT_GPIO1_0_15_IRQ=y + CONFIG_IMXRT_GPIO_IRQ=y + CONFIG_NETDEV_IOCTL=y + CONFIG_NETDEV_PHY_IOCTL=y + CONFIG_NSH_NETINIT_MONITOR=y + CONFIG_NSH_NETINIT_RETRYMSEC=2000 + CONFIG_NSH_NETINIT_SIGNO=18 + CONFIG_NSH_NETINIT_THREAD=y + CONFIG_NSH_NETINIT_THREAD_PRIORITY=80 + CONFIG_NSH_NETINIT_THREAD_STACKSIZE=1568 + + STATUS: As of this writing, I get a hardfault when I enable the PHY + interrupt so I suspect that there is something incorrect in that + pin configuration. + nsh: Configures the NuttShell (nsh) located at examples/nsh. This NSH diff --git a/configs/imxrt1050-evk/src/imxrt1050-evk.h b/configs/imxrt1050-evk/src/imxrt1050-evk.h index cfbd1721c68..f673e049d97 100644 --- a/configs/imxrt1050-evk/src/imxrt1050-evk.h +++ b/configs/imxrt1050-evk/src/imxrt1050-evk.h @@ -96,16 +96,24 @@ #define GPIO_SW8 (GPIO_INTERRUPT | GPIO_INT_FALLINGEDGE | \ GPIO_PORT5 | GPIO_PIN0 | IOMUX_SW8) -/* GPIOAD_B0_10 */ +/* Ethernet Interrupt: GPIOAD_B0_10 + * + * This pin has a week pull-up within the PHY, is open-drain, and requires + * an external 1k ohm pull-up resistor (present on the EVK). A falling + * edge then indicates a change in state of the PHY. + */ #define IOMUX_ENET_INT (IOMUX_SLEW_FAST | IOMUX_DRIVE_50OHM | \ - IOMUX_SPEED_MEDIUM | IOMUX_PULL_UP_100K | \ - _IOMUX_PULL_ENABLE) -#define GPIO_ENET_INT (GPIO_OUTPUT | GPIO_OUTPUT_ONE | \ + IOMUX_SPEED_MEDIUM | IOMUX_PULL_UP_100K) +#define GPIO_ENET_INT (GPIO_INTERRUPT | GPIO_INT_FALLINGEDGE | \ GPIO_PORT1 | GPIO_PIN10 | IOMUX_ENET_INT) #define GPIO_ENET_IRQ IMXRT_IRQ_GPIO1_10 -/* GPIOAD_B0_09 */ +/* Ethernet Reset: GPIOAD_B0_09 + * + * The #RST uses inverted logic. The initial value of zero will put the + * PHY into the reset state. + */ #define IOMUX_ENET_RST (IOMUX_SLEW_FAST | IOMUX_DRIVE_50OHM | \ IOMUX_SPEED_MEDIUM | IOMUX_PULL_UP_100K | \ diff --git a/configs/imxrt1050-evk/src/imxrt_ethernet.c b/configs/imxrt1050-evk/src/imxrt_ethernet.c index 69a55a9898f..3ea42fce543 100644 --- a/configs/imxrt1050-evk/src/imxrt_ethernet.c +++ b/configs/imxrt1050-evk/src/imxrt_ethernet.c @@ -50,6 +50,7 @@ #include #include +#include #include #include @@ -129,7 +130,7 @@ static void imxrt_enet_phy_enable(bool enable) * ************************************************************************************/ -void weak_function imxrt_phy_boardinitialize(void) +int imxrt_phy_boardinitialize(int intf) { #ifdef CONFIG_IMXRT_GPIO1_0_15_IRQ /* Configure the PHY interrupt pin */ @@ -138,10 +139,19 @@ void weak_function imxrt_phy_boardinitialize(void) imxrt_config_gpio(GPIO_ENET_INT); #endif - /* Configure the PHY reset pin. This will also take the PHY out of reset. */ + /* Configure the PHY reset pin. + * + * The #RST uses inverted logic. The initial value of zero will put the + * PHY into the reset state. + */ phyinfo("Configuring reset: %08x\n", GPIO_ENET_RST); imxrt_config_gpio(GPIO_ENET_RST); + + /* Take the PHY out of reset. */ + + imxrt_gpio_write(GPIO_ENET_RST, true); + return OK; } /**************************************************************************** @@ -211,7 +221,6 @@ int arch_phy_irq(FAR const char *intf, xcpt_t handler, void *arg, phy_enable_t *enable) { irqstate_t flags; - gpio_pinset_t pinset; phy_enable_t enabler; int irq; @@ -222,15 +231,13 @@ int arch_phy_irq(FAR const char *intf, xcpt_t handler, void *arg, if (strcmp(intf, IMXRT_ENET_DEVNAME) == 0) { - phyinfo("Select EMAC\n"); - pinset = GPIO_ENET_INT; - irq = GPIO_ENET_IRQ; - enabler = imxrt_enet_phy_enable; + irq = GPIO_ENET_IRQ; + enabler = imxrt_enet_phy_enable; } else { nerr("ERROR: Unsupported interface: %s\n", intf); - return NULL; + return -EINVAL; } /* Disable interrupts until we are done. This guarantees that the diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c index 669cf2fd7b0..59655d8f9d1 100644 --- a/drivers/net/skeleton.c +++ b/drivers/net/skeleton.c @@ -404,9 +404,9 @@ static void skel_receive(FAR struct skel_driver_s *priv) pkt_input(&priv->sk_dev); #endif - /* We only accept IP packets of the configured type and ARP packets */ - #ifdef CONFIG_NET_IPv4 + /* Check for an IPv4 packet */ + if (BUF->type == HTONS(ETHTYPE_IP)) { ninfo("IPv4 frame\n"); @@ -426,6 +426,8 @@ static void skel_receive(FAR struct skel_driver_s *priv) else #endif #ifdef CONFIG_NET_IPv6 + /* Check for an IPv6 packet */ + if (BUF->type == HTONS(ETHTYPE_IP6)) { ninfo("Iv6 frame\n"); @@ -442,6 +444,8 @@ static void skel_receive(FAR struct skel_driver_s *priv) else #endif #ifdef CONFIG_NET_ARP + /* Check for an ARP packet */ + if (BUF->type == htons(ETHTYPE_ARP)) { /* Dispatch ARP packet to the network layer */