diff --git a/drivers/ethernet/Kconfig.mcux b/drivers/ethernet/Kconfig.mcux index 8551f8c547d..fab557cbd01 100644 --- a/drivers/ethernet/Kconfig.mcux +++ b/drivers/ethernet/Kconfig.mcux @@ -8,6 +8,7 @@ menuconfig ETH_MCUX depends on HAS_MCUX_ENET select NOCACHE_MEMORY if HAS_MCUX_CACHE select ARM_MPU if CPU_CORTEX_M7 + select NET_POWER_MANAGEMENT if DEVICE_POWER_MANAGEMENT help Enable MCUX Ethernet driver. Note, this driver performs one shot PHY setup. There is no support for PHY disconnect, reconnect or diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index 979a6c0b4cb..d35f0b25fe2 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -34,6 +34,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "fsl_enet.h" #include "fsl_phy.h" +#ifdef CONFIG_NET_POWER_MANAGEMENT +#include "fsl_clock.h" +#include +#endif #define FREESCALE_OUI_B0 0x00 #define FREESCALE_OUI_B1 0x04 @@ -50,6 +54,8 @@ enum eth_mcux_phy_state { eth_mcux_phy_state_closing }; +static void eth_mcux_init(struct device *dev); + static const char * phy_state_name(enum eth_mcux_phy_state state) __attribute__((unused)); @@ -91,6 +97,11 @@ struct eth_context { * used for anything. */ struct net_if *iface; +#ifdef CONFIG_NET_POWER_MANAGEMENT + const char *clock_name; + clock_ip_name_t clock; + struct device *clock_dev; +#endif enet_handle_t enet_handle; #if defined(CONFIG_PTP_CLOCK_MCUX) struct device *ptp_clock; @@ -166,6 +177,60 @@ rx_buffer[CONFIG_ETH_MCUX_RX_BUFFERS][ETH_MCUX_BUFFER_SIZE]; static u8_t __aligned(ENET_BUFF_ALIGNMENT) tx_buffer[CONFIG_ETH_MCUX_TX_BUFFERS][ETH_MCUX_BUFFER_SIZE]; +#ifdef CONFIG_NET_POWER_MANAGEMENT +static void eth_mcux_phy_enter_reset(struct eth_context *context); +void eth_mcux_phy_stop(struct eth_context *context); + +static int eth_mcux_device_pm_control(struct device *dev, u32_t command, + void *context, device_pm_cb cb, void *arg) +{ + struct eth_context *eth_ctx = (struct eth_context *)dev->driver_data; + int ret = 0; + + if (!eth_ctx->clock_dev) { + LOG_ERR("No CLOCK dev"); + + ret = -EIO; + goto out; + } + + if (command == DEVICE_PM_SET_POWER_STATE) { + if (*(u32_t *)context == DEVICE_PM_SUSPEND_STATE) { + LOG_DBG("Suspending"); + + eth_mcux_phy_enter_reset(eth_ctx); + eth_mcux_phy_stop(eth_ctx); + + ENET_Reset(eth_ctx->base); + ENET_Deinit(eth_ctx->base); + clock_control_off(eth_ctx->clock_dev, + (clock_control_subsys_t)eth_ctx->clock); + } else if (*(u32_t *)context == DEVICE_PM_ACTIVE_STATE) { + LOG_DBG("Resuming"); + + clock_control_on(eth_ctx->clock_dev, + (clock_control_subsys_t)eth_ctx->clock); + eth_mcux_init(dev); + net_if_resume(eth_ctx->iface); + } + } else { + return -EINVAL; + } + +out: + if (cb) { + cb(dev, ret, context, arg); + } + + return ret; +} + +#define ETH_MCUX_PM_FUNC eth_mcux_device_pm_control + +#else +#define ETH_MCUX_PM_FUNC device_pm_control_nop +#endif /* CONFIG_NET_POWER_MANAGEMENT */ + static void eth_mcux_decode_duplex_and_speed(u32_t status, phy_duplex_t *p_phy_duplex, phy_speed_t *p_phy_speed) @@ -846,7 +911,7 @@ static void generate_eth1_unique_mac(u8_t *mac_addr) } #endif -static int eth_init(struct device *dev) +static void eth_mcux_init(struct device *dev) { struct eth_context *context = dev->driver_data; enet_config_t enet_config; @@ -869,17 +934,7 @@ static int eth_init(struct device *dev) u8_t mdns_multicast[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFB }; #endif -#if defined(CONFIG_PTP_CLOCK_MCUX) - ts_tx_rd = 0; - ts_tx_wr = 0; - (void)memset(ts_tx_pkt, 0, sizeof(ts_tx_pkt)); -#endif - - k_sem_init(&context->tx_buf_sem, - 0, CONFIG_ETH_MCUX_TX_BUFFERS); - k_work_init(&context->phy_work, eth_mcux_phy_work); - k_delayed_work_init(&context->delayed_phy_work, - eth_mcux_delayed_phy_work); + context->phy_state = eth_mcux_phy_state_initial; sys_clock = CLOCK_GetFreq(kCLOCK_CoreSysClk); @@ -888,30 +943,22 @@ static int eth_init(struct device *dev) enet_config.interrupt |= kENET_TxFrameInterrupt; enet_config.interrupt |= kENET_MiiInterrupt; -#ifdef CONFIG_ETH_MCUX_PROMISCUOUS_MODE - enet_config.macSpecialConfig |= kENET_ControlPromiscuousEnable; -#endif - - /* Initialize/override OUI which may not be correct in - * devicetree. - */ - context->mac_addr[0] = FREESCALE_OUI_B0; - context->mac_addr[1] = FREESCALE_OUI_B1; - context->mac_addr[2] = FREESCALE_OUI_B2; - if (context->generate_mac) { - context->generate_mac(context->mac_addr); + if (IS_ENABLED(CONFIG_ETH_MCUX_PROMISCUOUS_MODE)) { + enet_config.macSpecialConfig |= kENET_ControlPromiscuousEnable; } -#if defined(CONFIG_NET_VLAN) - enet_config.macSpecialConfig |= kENET_ControlVLANTagEnable; -#endif + if (IS_ENABLED(CONFIG_NET_VLAN)) { + enet_config.macSpecialConfig |= kENET_ControlVLANTagEnable; + } -#if defined(CONFIG_ETH_MCUX_HW_ACCELERATION) - enet_config.txAccelerConfig |= - kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled; - enet_config.rxAccelerConfig |= - kENET_RxAccelIpCheckEnabled | kENET_RxAccelProtoCheckEnabled; -#endif + if (IS_ENABLED(CONFIG_ETH_MCUX_HW_ACCELERATION)) { + enet_config.txAccelerConfig |= + kENET_TxAccelIpCheckEnabled | + kENET_TxAccelProtoCheckEnabled; + enet_config.rxAccelerConfig |= + kENET_RxAccelIpCheckEnabled | + kENET_RxAccelProtoCheckEnabled; + } ENET_Init(context->base, &context->enet_handle, @@ -920,6 +967,7 @@ static int eth_init(struct device *dev) context->mac_addr, sys_clock); + #if defined(CONFIG_PTP_CLOCK_MCUX) ENET_AddMulticastGroup(context->base, ptp_multicast); @@ -935,6 +983,7 @@ static int eth_init(struct device *dev) ENET_Ptp1588Configure(context->base, &context->enet_handle, &context->ptp_config); #endif + #if defined(CONFIG_MDNS_RESPONDER) || defined(CONFIG_MDNS_RESOLVER) ENET_AddMulticastGroup(context->base, mdns_multicast); #endif @@ -944,15 +993,48 @@ static int eth_init(struct device *dev) /* handle PHY setup after SMI initialization */ eth_mcux_phy_setup(context); - LOG_DBG("%s MAC %02x:%02x:%02x:%02x:%02x:%02x", - eth_name(context->base), - context->mac_addr[0], context->mac_addr[1], - context->mac_addr[2], context->mac_addr[3], - context->mac_addr[4], context->mac_addr[5]); - ENET_SetCallback(&context->enet_handle, eth_callback, dev); eth_mcux_phy_start(context); +} + +static int eth_init(struct device *dev) +{ + struct eth_context *context = dev->driver_data; + +#if defined(CONFIG_PTP_CLOCK_MCUX) + ts_tx_rd = 0; + ts_tx_wr = 0; + (void)memset(ts_tx_pkt, 0, sizeof(ts_tx_pkt)); +#endif + +#if defined(CONFIG_NET_POWER_MANAGEMENT) + context->clock_dev = device_get_binding(context->clock_name); +#endif + + k_sem_init(&context->tx_buf_sem, + 0, CONFIG_ETH_MCUX_TX_BUFFERS); + k_work_init(&context->phy_work, eth_mcux_phy_work); + k_delayed_work_init(&context->delayed_phy_work, + eth_mcux_delayed_phy_work); + + + /* Initialize/override OUI which may not be correct in + * devicetree. + */ + context->mac_addr[0] = FREESCALE_OUI_B0; + context->mac_addr[1] = FREESCALE_OUI_B1; + context->mac_addr[2] = FREESCALE_OUI_B2; + if (context->generate_mac) { + context->generate_mac(context->mac_addr); + } + + eth_mcux_init(dev); + + LOG_DBG("MAC %02x:%02x:%02x:%02x:%02x:%02x", + context->mac_addr[0], context->mac_addr[1], + context->mac_addr[2], context->mac_addr[3], + context->mac_addr[4], context->mac_addr[5]); return 0; } @@ -1110,6 +1192,10 @@ static void eth_0_config_func(void); static struct eth_context eth_0_context = { .base = ENET, +#if defined(CONFIG_NET_POWER_MANAGEMENT) + .clock_name = DT_INST_0_NXP_KINETIS_ETHERNET_CLOCK_CONTROLLER, + .clock = kCLOCK_Enet0, +#endif .config_func = eth_0_config_func, .phy_addr = 0U, .phy_duplex = kPHY_FullDuplex, @@ -1127,7 +1213,7 @@ static struct eth_context eth_0_context = { }; ETH_NET_DEVICE_INIT(eth_mcux_0, DT_ETH_MCUX_0_NAME, eth_init, - device_pm_control_nop, ð_0_context, NULL, + ETH_MCUX_PM_FUNC, ð_0_context, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU); static void eth_0_config_func(void) @@ -1168,6 +1254,10 @@ static void eth_1_config_func(void); static struct eth_context eth_1_context = { .base = ENET2, +#if defined(CONFIG_NET_POWER_MANAGEMENT) + .clock_name = DT_INST_1_NXP_KINETIS_ETHERNET_CLOCK_CONTROLLER, + .clock = kCLOCK_Enet2, +#endif .config_func = eth_1_config_func, .phy_addr = 0U, .phy_duplex = kPHY_FullDuplex, @@ -1185,7 +1275,7 @@ static struct eth_context eth_1_context = { }; ETH_NET_DEVICE_INIT(eth_mcux_1, DT_ETH_MCUX_1_NAME, eth_init, - device_pm_control_nop, ð_1_context, NULL, + ETH_MCUX_PM_FUNC, ð_1_context, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU); static void eth_1_config_func(void)