drivers/ethernet: Add support for power management into MCUX
Requesting the clock controller to switch on or off the device. Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
aba61cc105
commit
db6f896c00
2 changed files with 132 additions and 41 deletions
|
@ -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
|
||||
|
|
|
@ -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 <drivers/clock_control.h>
|
||||
#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
|
||||
if (IS_ENABLED(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 defined(CONFIG_NET_VLAN)
|
||||
if (IS_ENABLED(CONFIG_NET_VLAN)) {
|
||||
enet_config.macSpecialConfig |= kENET_ControlVLANTagEnable;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ETH_MCUX_HW_ACCELERATION)
|
||||
if (IS_ENABLED(CONFIG_ETH_MCUX_HW_ACCELERATION)) {
|
||||
enet_config.txAccelerConfig |=
|
||||
kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled;
|
||||
kENET_TxAccelIpCheckEnabled |
|
||||
kENET_TxAccelProtoCheckEnabled;
|
||||
enet_config.rxAccelerConfig |=
|
||||
kENET_RxAccelIpCheckEnabled | kENET_RxAccelProtoCheckEnabled;
|
||||
#endif
|
||||
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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue