From 90ece2d9171a2b7604ab6daffdd1417cf23f9781 Mon Sep 17 00:00:00 2001 From: jjlange Date: Fri, 5 Apr 2019 21:16:03 +0000 Subject: [PATCH] Merged in jjlange/nuttx/lpc17_ethupdates2 (pull request #849) Added support for Ethernet PHY ioctl() on LPC17xx. * Added support for Ethernet PHY ioctl() on LPC17xx. * Fixed whitespace. * One more time. Approved-by: Gregory Nutt --- arch/arm/src/lpc17xx/lpc17_ethernet.c | 188 ++++++++++++++++++++++++-- 1 file changed, 176 insertions(+), 12 deletions(-) diff --git a/arch/arm/src/lpc17xx/lpc17_ethernet.c b/arch/arm/src/lpc17xx/lpc17_ethernet.c index bd6abc4c57..983b249743 100644 --- a/arch/arm/src/lpc17xx/lpc17_ethernet.c +++ b/arch/arm/src/lpc17xx/lpc17_ethernet.c @@ -39,6 +39,7 @@ #include #if defined(CONFIG_NET) && defined(CONFIG_LPC17_ETHERNET) +#include #include #include @@ -72,7 +73,7 @@ #include -/* Does this chip have and Ethernet controller? */ +/* Does this chip have an Ethernet controller? */ #if LPC17_NETHCONTROLLERS > 0 @@ -240,6 +241,40 @@ # endif #endif +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +# if defined( CONFIG_ETH0_PHY_AM79C874) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KS8721) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8041) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8051) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8061) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_KSZ8081) +# define MII_INT_REG MII_KSZ8081_INT +# define MII_INT_SETEN MII_KSZ80x1_INT_LDEN | MII_KSZ80x1_INT_LUEN +# define MII_INT_CLREN 0 +# elif defined( CONFIG_ETH0_PHY_KSZ90x1) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_DP83848C) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8720) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8740) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8740A) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_LAN8742A) +# error missing logic +# elif defined( CONFIG_ETH0_PHY_DM9161) +# error missing logic +# else +# error unknown PHY +# endif +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -361,6 +396,11 @@ static int lpc17_addmac(struct net_driver_s *dev, const uint8_t *mac); static int lpc17_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif +#ifdef CONFIG_NETDEV_IOCTL +static int lpc17_eth_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + /* Initialization functions */ #if defined(CONFIG_LPC17_NET_REGDEBUG) && defined(CONFIG_DEBUG_GPIO_INFO) @@ -378,6 +418,9 @@ static void lpc17_showmii(uint8_t phyaddr, const char *msg); # define lpc17_showmii(phyaddr,msg) # endif +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int lpc17_phyintenable(FAR struct lpc17_driver_s *priv); +#endif static void lpc17_phywrite(uint8_t phyaddr, uint8_t regaddr, uint16_t phydata); static uint16_t lpc17_phyread(uint8_t phyaddr, uint8_t regaddr); @@ -2077,6 +2120,124 @@ static int lpc17_rmmac(struct net_driver_s *dev, const uint8_t *mac) } #endif +/**************************************************************************** + * Name: lpc17_eth_ioctl + * + * Description: + * Handle network IOCTL commands directed to this device. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - The IOCTL command + * arg - The argument for the IOCTL command + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int lpc17_eth_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg) +{ +#ifdef CONFIG_NETDEV_PHY_IOCTL + struct lpc17_driver_s *priv = (struct lpc17_driver_s *)dev->d_private; +#endif + int ret; + + /* Decode and dispatch the driver-specific IOCTL command */ + + 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 = lpc17_phyintenable(priv); + } + } + break; +#endif + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->lp_phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->val_out = lpc17_phyread(priv->lp_phyaddr, req->reg_num); + ret = OK; + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + lpc17_phywrite(priv->lp_phyaddr, req->reg_num, req->val_in); + ret = OK; + } + break; +#endif /* ifdef CONFIG_NETDEV_PHY_IOCTL */ + + default: + nerr("ERROR: Unrecognized IOCTL command: %d\n", command); + return -ENOTTY; /* Special return value for this case */ + } + + return OK; +} +#endif + +/**************************************************************************** + * Function: lpc17_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 lpc17_phyintenable(struct lpc17_driver_s *priv) +{ + uint16_t phyval; + + phyval = lpc17_phyread(priv->lp_phyaddr, MII_INT_REG); + + /* Enable link up/down interrupts */ + + lpc17_phywrite(priv->lp_phyaddr, MII_INT_REG, + (phyval & ~MII_INT_CLREN) | MII_INT_SETEN); + + return OK; +} +#endif + /**************************************************************************** * Name: lpc17_showpins * @@ -3051,26 +3212,29 @@ static inline int lpc17_ethinitialize(int intf) /* Initialize the driver structure */ memset(priv, 0, sizeof(struct lpc17_driver_s)); - priv->lp_dev.d_buf = pktbuf; /* Single packet buffer */ - priv->lp_dev.d_ifup = lpc17_ifup; /* I/F down callback */ - priv->lp_dev.d_ifdown = lpc17_ifdown; /* I/F up (new IP address) callback */ - priv->lp_dev.d_txavail = lpc17_txavail; /* New TX data callback */ + priv->lp_dev.d_buf = pktbuf; /* Single packet buffer */ + priv->lp_dev.d_ifup = lpc17_ifup; /* I/F down callback */ + priv->lp_dev.d_ifdown = lpc17_ifdown; /* I/F up (new IP address) callback */ + priv->lp_dev.d_txavail = lpc17_txavail; /* New TX data callback */ #ifdef CONFIG_NET_MCASTGROUP - priv->lp_dev.d_addmac = lpc17_addmac; /* Add multicast MAC address */ - priv->lp_dev.d_rmmac = lpc17_rmmac; /* Remove multicast MAC address */ + priv->lp_dev.d_addmac = lpc17_addmac; /* Add multicast MAC address */ + priv->lp_dev.d_rmmac = lpc17_rmmac; /* Remove multicast MAC address */ #endif - priv->lp_dev.d_private = (void *)priv; /* Used to recover private state from dev */ +#ifdef CONFIG_NETDEV_IOCTL + priv->lp_dev.d_ioctl = lpc17_eth_ioctl; /* Handle network IOCTL commands */ +#endif + priv->lp_dev.d_private = (void *)priv; /* Used to recover private state from dev */ #if CONFIG_LPC17_NINTERFACES > 1 # error "A mechanism to associate base address an IRQ with an interface is needed" - priv->lp_base = ??; /* Ethernet controller base address */ - priv->lp_irq = ??; /* Ethernet controller IRQ number */ + priv->lp_base = ??; /* Ethernet controller base address */ + priv->lp_irq = ??; /* Ethernet controller IRQ number */ #endif /* Create a watchdog for timing polling for and timing of transmissions */ - priv->lp_txpoll = wd_create(); /* Create periodic poll timer */ - priv->lp_txtimeout = wd_create(); /* Create TX timeout timer */ + priv->lp_txpoll = wd_create(); /* Create periodic poll timer */ + priv->lp_txtimeout = wd_create(); /* Create TX timeout timer */ /* Reset the Ethernet controller and leave in the ifdown statue. The * Ethernet controller will be properly re-initialized each time