diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c index 2197665b32..0d86cd605a 100644 --- a/arch/arm/src/stm32/stm32_eth.c +++ b/arch/arm/src/stm32/stm32_eth.c @@ -665,6 +665,9 @@ static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv); /* PHY Initialization */ +#ifdef CONFIG_NETDEV_PHY_IOCTL +static int stm32_ioctl(int cmd, struct mii_ioctl_data *req); +#endif static int stm32_phyread(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t *value); static int stm32_phywrite(uint16_t phydevaddr, uint16_t phyregaddr, uint16_t value); #ifdef CONFIG_ETH0_PHY_DM9161 @@ -2475,6 +2478,63 @@ static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv) stm32_putreg((uint32_t)priv->rxtable, STM32_ETH_DMARDLAR); } +/**************************************************************************** + * Function: stm32_ioctl + * + * Description: + * Executes the SIOCxMIIxxx command and responds using the request struct + * that must be provided as its 2nd parameter. + * + * When called with SIOCGMIIPHY it will get the PHY address for the device + * and write it to the req->phy_id field of the request struct. + * + * When called with SIOCGMIIREG it will read a register of the PHY that is + * specified using the req->reg_no struct field and then write its output + * to the req->val_out field. + * + * When called with SIOCSMIIREG it will write to a register of the PHY that + * is specified using the req->reg_no struct field and use req->val_in as + * its input. + * + * Parameters: + * cmd - SIOCxMIIxxx command code + * req - request structure also used to return values + * + * Returned Value: Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_PHY_IOCTL +static int stm32_ioctl(int cmd, struct mii_ioctl_data *req) +{ + int ret = -ENOTTY; + + switch (cmd) + { + case SIOCGMIIPHY: /* Get MII PHY address */ + req->phy_id = CONFIG_STM32_PHYADDR; + ret = OK; + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + ret = stm32_phyread(req->phy_id, req->reg_num, &req->val_out); + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + ret = stm32_phywrite(req->phy_id, req->reg_num, req->val_in); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + /**************************************************************************** * Function: stm32_phyread * @@ -3460,6 +3520,9 @@ int stm32_ethinitialize(int intf) #ifdef CONFIG_NET_IGMP priv->dev.d_addmac = stm32_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = stm32_rmmac; /* Remove multicast MAC address */ +#endif +#ifdef CONFIG_NETDEV_PHY_IOCTL + priv->dev.d_ioctl = stm32_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void*)g_stm32ethmac; /* Used to recover private state from dev */ diff --git a/include/net/if.h b/include/net/if.h index eae6bcb3fc..bad4a21240 100644 --- a/include/net/if.h +++ b/include/net/if.h @@ -57,11 +57,22 @@ #define IFF_RUNNING (1 << 2) #define IFF_NOARP (1 << 7) - /******************************************************************************************* * Public Type Definitions *******************************************************************************************/ +/* Part of the I/F request used to read from or write to the MII/PHY management + * interface when SIOCxMIIREG ioctl was called. + */ + +struct mii_ioctl_data +{ + uint16_t phy_id; /* PHY device address */ + uint16_t reg_num; /* PHY register address */ + uint16_t val_in; /* PHY input data */ + uint16_t val_out; /* PHY output data */ +}; + /* This is the newer form if the I/F request structure that can be used with both IPv4 * and IPv6. */ @@ -79,6 +90,7 @@ struct lifreq int lifru_count; /* Number of devices */ int lifru_mtu; /* MTU size */ uint8_t lifru_flags; /* Interface flags */ + struct mii_ioctl_data lifru_mii_data; /* MII request data */ } lifr_ifru; }; @@ -90,6 +102,10 @@ struct lifreq #define lifr_mtu lifr_ifru.lifru_mtu /* MTU */ #define lifr_count lifr_ifru.lifru_count /* Number of devices */ #define lifr_flags lifr_ifru.lifru_flags /* interface flags */ +#define lifr_mii_phy_id lifr_ifru.lifru_mii_data.phy_id /* PHY device address */ +#define lifr_mii_reg_num lifr_ifru.lifru_mii_data.reg_num /* PHY register address */ +#define lifr_mii_val_in lifr_ifru.lifru_mii_data.val_in /* PHY input data */ +#define lifr_mii_val_out lifr_ifru.lifru_mii_data.val_out /* PHY output data */ /* This is the older I/F request that should only be used with IPv4. However, since * NuttX only supports IPv4 or 6 (not both), we can force the older structure to @@ -110,6 +126,7 @@ struct ifreq int ifru_count; /* Number of devices */ int ifru_mtu; /* MTU size */ uint8_t ifru_flags; /* Interface flags */ + struct mii_ioctl_data ifru_mii_data; /* MII request data */ } ifr_ifru; }; @@ -121,6 +138,10 @@ struct ifreq #define ifr_mtu ifr_ifru.ifru_mtu /* MTU */ #define ifr_count ifr_ifru.ifru_count /* Number of devices */ #define ifr_flags ifr_ifru.ifru_flags /* interface flags */ +#define ifr_mii_phy_id ifr_ifru.ifru_mii_data.phy_id /* PHY device address */ +#define ifr_mii_reg_num ifr_ifru.ifru_mii_data.reg_num /* PHY register address */ +#define ifr_mii_val_in ifr_ifru.ifru_mii_data.val_in /* PHY input data */ +#define ifr_mii_val_out ifr_ifru.ifru_mii_data.val_out /* PHY output data */ #else /* CONFIG_NET_IPv6 */ @@ -134,6 +155,10 @@ struct ifreq #define ifr_mtu lifr_ifru.lifru_mtu /* MTU */ #define ifr_count lifr_ifru.lifru_count /* Number of devices */ #define ifr_flags lifr_ifru.lifru_flags /* interface flags */ +#define ifr_mii_phy_id lifr_ifru.lifru_mii_data.phy_id /* PHY device address */ +#define ifr_mii_reg_num lifr_ifru.lifru_mii_data.reg_num /* PHY register address */ +#define ifr_mii_val_in lifr_ifru.lifru_mii_data.val_in /* PHY input data */ +#define ifr_mii_val_out lifr_ifru.lifru_mii_data.val_out /* PHY output data */ #endif /* CONFIG_NET_IPv6 */ diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h index 7fbcc3b201..7c2e1cb497 100644 --- a/include/nuttx/net/ioctl.h +++ b/include/nuttx/net/ioctl.h @@ -160,6 +160,12 @@ #define SIOCSIWPMKSA _SIOC(0x0041) /* PMKSA cache operation */ +/* MDIO/MCD *****************************************************************/ + +#define SIOCGMIIPHY _SIOC(0x0042) /* Get address of MII PHY in use */ +#define SIOCGMIIREG _SIOC(0x0043) /* Get a MII register via MDIO */ +#define SIOCSMIIREG _SIOC(0x0044) /* Set a MII register via MDIO */ + /**************************************************************************** * Type Definitions ****************************************************************************/ diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 0537587381..cc781a77df 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -187,6 +187,9 @@ struct uip_driver_s int (*d_addmac)(struct uip_driver_s *dev, FAR const uint8_t *mac); int (*d_rmmac)(struct uip_driver_s *dev, FAR const uint8_t *mac); #endif +#ifdef CONFIG_NETDEV_PHY_IOCTL + int (*d_ioctl)(int cmd, struct mii_ioctl_data *req); +#endif /* Drivers may attached device-specific, private information */ diff --git a/net/Kconfig b/net/Kconfig index 294ea523e4..8440b4dc1d 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -73,6 +73,12 @@ config NET_SOCKOPTS ---help--- Enable or disable support for socket options +config NETDEV_PHY_IOCTL + bool "Enable PHY ioctl()" + default n + ---help--- + Enable support for ioctl() commands to access PHY registers" + if NET_SOCKOPTS config NET_SOLINGER diff --git a/net/netdev_ioctl.c b/net/netdev_ioctl.c index 1505e668fe..ec216a1e47 100644 --- a/net/netdev_ioctl.c +++ b/net/netdev_ioctl.c @@ -422,6 +422,21 @@ static int netdev_ifrioctl(FAR struct socket *psock, int cmd, # error "IOCTL Commands not implemented" #endif +#ifdef CONFIG_NETDEV_PHY_IOCTL + case SIOCGMIIPHY: /* Get address of MII PHY in use */ + case SIOCGMIIREG: /* Get MII register via MDIO */ + case SIOCSMIIREG: /* Set MII register via MDIO */ + { + dev = netdev_ifrdev(req); + if (dev && dev->d_ioctl) + { + struct mii_ioctl_data *mii_data = &req->ifr_ifru.ifru_mii_data; + ret = dev->d_ioctl(cmd, mii_data); + } + } + break; +#endif + default: { ret = -ENOTTY;