drivers: ethernet: add NXP i.MX NETC driver

Added NXP i.MX NETC driver based on NXP MCUX SDK driver APIs.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
This commit is contained in:
Yangbo Lu 2024-06-20 16:25:45 +09:00 committed by Henrik Brix Andersen
parent 4986809581
commit 553079350c
7 changed files with 753 additions and 0 deletions

View file

@ -47,6 +47,11 @@ if(CONFIG_ETH_NXP_S32_NETC)
zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_S32_NETC_VSI_ENABLED eth_nxp_s32_netc_vsi.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_S32_NETC_VSI_ENABLED eth_nxp_s32_netc_vsi.c)
endif() endif()
if(CONFIG_ETH_NXP_IMX_NETC)
zephyr_library_sources(eth_nxp_imx_netc.c)
zephyr_library_sources(eth_nxp_imx_netc_psi.c)
endif()
zephyr_library_sources_ifdef(CONFIG_ETH_NXP_S32_GMAC eth_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_ETH_NXP_S32_GMAC eth_nxp_s32_gmac.c)
zephyr_library_sources_ifdef(CONFIG_ETH_NUMAKER eth_numaker.c) zephyr_library_sources_ifdef(CONFIG_ETH_NUMAKER eth_numaker.c)

View file

@ -65,6 +65,7 @@ source "drivers/ethernet/Kconfig.w5500"
source "drivers/ethernet/Kconfig.dsa" source "drivers/ethernet/Kconfig.dsa"
source "drivers/ethernet/Kconfig.xlnx_gem" source "drivers/ethernet/Kconfig.xlnx_gem"
source "drivers/ethernet/Kconfig.cyclonev" source "drivers/ethernet/Kconfig.cyclonev"
source "drivers/ethernet/Kconfig.nxp_imx_netc"
source "drivers/ethernet/Kconfig.nxp_s32_netc" source "drivers/ethernet/Kconfig.nxp_s32_netc"
source "drivers/ethernet/Kconfig.nxp_s32_gmac" source "drivers/ethernet/Kconfig.nxp_s32_gmac"
source "drivers/ethernet/Kconfig.smsc91x" source "drivers/ethernet/Kconfig.smsc91x"

View file

@ -0,0 +1,87 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
menuconfig ETH_NXP_IMX_NETC
bool "NXP IMX Ethernet and Network Controller (NETC) driver"
default y
depends on DT_HAS_NXP_IMX_NETC_PSI_ENABLED
select MDIO
select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT
help
Enable Ethernet and Network Controller (NETC) driver for NXP IMX SoCs.
if ETH_NXP_IMX_NETC
config ETH_NXP_IMX_MSGINTR
int "Message Interrupt module select"
default 1
help
Message Interrupt module select.
config ETH_NXP_IMX_RX_THREAD_PRIO
int "RX thread priority"
default 2
help
RX thread priority. RX thread is a cooperative thread.
config ETH_NXP_IMX_RX_THREAD_STACK_SIZE
int "RX thread stack size"
default 1500
help
RX thread stack size.
config ETH_NXP_IMX_RX_BUDGET
int "RX thread budget"
default 128
range 1 1024
help
The budget parameter places a limit on the amount of work the driver may
do in the RX thread before yielding the processor, in case there is more
work to do. This is to prevent the RX thread to starve other threads. Each
received frame counts as one unit of work.
config ETH_NXP_IMX_TX_RING_NUM
int "TX ring number"
default 1
range 1 1023
help
TX ring number used. The actual maximum value may varies from platforms.
config ETH_NXP_IMX_TX_RING_LEN
int "TX ring length"
default 8
range 8 256
help
Length of the TX ring. The value must be a multiple of 8.
config ETH_NXP_IMX_TX_RING_BUF_SIZE
int "TX ring data buffer size"
default 1000
range 64 1536
help
Size, in bytes, of the TX data buffer. The size must be big enough to
store one complete Ethernet frame, and be a multiple of 8.
config ETH_NXP_IMX_RX_RING_NUM
int "RX ring number"
default 1
range 1 1023
help
RX ring number used. The actual maximum value may varies from platforms.
config ETH_NXP_IMX_RX_RING_LEN
int "RX ring length"
default 8
range 8 256
help
Length of the RX ring. The value must be a multiple of 8.
config ETH_NXP_IMX_RX_RING_BUF_SIZE
int "RX ring data buffer size"
default 1518
range 64 1536
help
Size, in bytes, of the RX data buffer. The size must be big enough to
store one complete Ethernet frame, and be a multiple of 8.
endif # ETH_NXP_IMX_NETC

View file

@ -0,0 +1,321 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(nxp_imx_eth);
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/mbox.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/net/ethernet.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/net_pkt.h>
#include <zephyr/net/phy.h>
#include <ethernet/eth_stats.h>
#include "eth.h"
#include "eth_nxp_imx_netc_priv.h"
const struct device *netc_dev_list[NETC_DRV_MAX_INST_SUPPORT];
static int netc_eth_rx(const struct device *dev)
{
struct netc_eth_data *data = dev->data;
struct net_pkt *pkt;
int key;
int ret = 0;
status_t result;
uint32_t length;
key = irq_lock();
/* Check rx frame */
result = EP_GetRxFrameSize(&data->handle, 0, &length);
if (result == kStatus_NETC_RxFrameEmpty) {
ret = -ENOBUFS;
goto out;
}
if (result != kStatus_Success) {
LOG_ERR("Error on received frame");
ret = -EIO;
goto out;
}
/* Receive frame */
result = EP_ReceiveFrameCopy(&data->handle, 0, data->rx_frame, length, NULL);
if (result != kStatus_Success) {
LOG_ERR("Error on received frame");
ret = -EIO;
goto out;
}
/* Copy to pkt */
pkt = net_pkt_rx_alloc_with_buffer(data->iface, length, AF_UNSPEC, 0, NETC_TIMEOUT);
if (!pkt) {
eth_stats_update_errors_rx(data->iface);
ret = -ENOBUFS;
goto out;
}
ret = net_pkt_write(pkt, data->rx_frame, length);
if (ret) {
eth_stats_update_errors_rx(data->iface);
net_pkt_unref(pkt);
goto out;
}
/* Send to upper layer */
ret = net_recv_data(data->iface, pkt);
if (ret < 0) {
eth_stats_update_errors_rx(data->iface);
net_pkt_unref(pkt);
LOG_ERR("Failed to enqueue frame into rx queue: %d", ret);
}
out:
irq_unlock(key);
return ret;
}
static void netc_eth_rx_thread(void *arg1, void *unused1, void *unused2)
{
const struct device *dev = (const struct device *)arg1;
struct netc_eth_data *data = dev->data;
int ret;
int work;
ARG_UNUSED(unused1);
ARG_UNUSED(unused2);
while (1) {
ret = k_sem_take(&data->rx_sem, K_FOREVER);
if (ret != 0) {
LOG_ERR("Take rx_sem error: %d", ret);
continue;
}
work = 0;
while (netc_eth_rx(dev) != -ENOBUFS) {
if (++work == CONFIG_ETH_NXP_IMX_RX_BUDGET) {
/* more work to do, reschedule */
work = 0;
k_yield();
}
}
}
}
static void msgintr_isr(void)
{
uint32_t irqs = NETC_MSGINTR->MSI[NETC_MSGINTR_CHANNEL].MSIR;
for (int i = 0; i < NETC_DRV_MAX_INST_SUPPORT; i++) {
const struct device *dev = netc_dev_list[i];
const struct netc_eth_config *config;
struct netc_eth_data *data;
if (!dev) {
return;
}
config = dev->config;
data = dev->data;
/* Transmit interrupt */
if (irqs & (1 << config->tx_intr_msg_data)) {
EP_CleanTxIntrFlags(&data->handle, 1, 0);
data->tx_done = true;
}
/* Receive interrupt */
if (irqs & (1 << config->rx_intr_msg_data)) {
EP_CleanRxIntrFlags(&data->handle, 1);
k_sem_give(&data->rx_sem);
}
}
SDK_ISR_EXIT_BARRIER;
}
static status_t netc_eth_reclaim_callback(ep_handle_t *handle, uint8_t ring,
netc_tx_frame_info_t *frameInfo, void *userData)
{
struct netc_eth_data *data = userData;
data->tx_info = *frameInfo;
return kStatus_Success;
}
int netc_eth_init_common(const struct device *dev)
{
const struct netc_eth_config *config = dev->config;
struct netc_eth_data *data = dev->data;
netc_msix_entry_t msix_entry[NETC_MSIX_ENTRY_NUM];
netc_rx_bdr_config_t rx_bdr_config = {0};
netc_tx_bdr_config_t tx_bdr_config = {0};
netc_bdr_config_t bdr_config = {0};
ep_config_t ep_config;
uint32_t msg_addr;
status_t result;
config->bdr_init(&bdr_config, &rx_bdr_config, &tx_bdr_config);
/* MSIX entry configuration */
msg_addr = MSGINTR_GetIntrSelectAddr(NETC_MSGINTR, NETC_MSGINTR_CHANNEL);
msix_entry[NETC_TX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit;
msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgAddr = msg_addr;
msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgData = config->tx_intr_msg_data;
msix_entry[NETC_RX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit;
msix_entry[NETC_RX_MSIX_ENTRY_IDX].msgAddr = msg_addr;
msix_entry[NETC_RX_MSIX_ENTRY_IDX].msgData = config->rx_intr_msg_data;
if (!irq_is_enabled(NETC_MSGINTR_IRQ)) {
IRQ_CONNECT(NETC_MSGINTR_IRQ, 0, msgintr_isr, 0, 0);
irq_enable(NETC_MSGINTR_IRQ);
}
/* Endpoint configuration. */
EP_GetDefaultConfig(&ep_config);
ep_config.si = config->si_idx;
ep_config.siConfig.txRingUse = 1;
ep_config.siConfig.rxRingUse = 1;
ep_config.userData = data;
ep_config.reclaimCallback = netc_eth_reclaim_callback;
ep_config.msixEntry = &msix_entry[0];
ep_config.entryNum = NETC_MSIX_ENTRY_NUM;
ep_config.port.ethMac.miiMode = kNETC_RmiiMode;
ep_config.port.ethMac.miiSpeed = kNETC_MiiSpeed100M;
ep_config.port.ethMac.miiDuplex = kNETC_MiiFullDuplex;
ep_config.rxCacheMaintain = true;
ep_config.txCacheMaintain = true;
config->generate_mac(&data->mac_addr[0]);
result = EP_Init(&data->handle, &data->mac_addr[0], &ep_config, &bdr_config);
if (result != kStatus_Success) {
return -ENOBUFS;
}
for (int i = 0; i < NETC_DRV_MAX_INST_SUPPORT; i++) {
if (!netc_dev_list[i]) {
netc_dev_list[i] = dev;
break;
}
}
/* Unmask MSIX message interrupt. */
EP_MsixSetEntryMask(&data->handle, NETC_TX_MSIX_ENTRY_IDX, false);
EP_MsixSetEntryMask(&data->handle, NETC_RX_MSIX_ENTRY_IDX, false);
k_mutex_init(&data->tx_mutex);
k_sem_init(&data->rx_sem, 0, 1);
k_thread_create(&data->rx_thread, data->rx_thread_stack,
K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), netc_eth_rx_thread,
(void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_ETH_NXP_IMX_RX_THREAD_PRIO), 0,
K_NO_WAIT);
k_thread_name_set(&data->rx_thread, "netc_eth_rx");
return 0;
}
int netc_eth_tx(const struct device *dev, struct net_pkt *pkt)
{
struct netc_eth_data *data = dev->data;
netc_buffer_struct_t buff = {.buffer = data->tx_buff, .length = sizeof(data->tx_buff)};
netc_frame_struct_t frame = {.buffArray = &buff, .length = 1};
size_t pkt_len = net_pkt_get_len(pkt);
status_t result;
int ret;
__ASSERT(pkt, "Packet pointer is NULL");
k_mutex_lock(&data->tx_mutex, K_FOREVER);
/* Copy packet to tx buffer */
buff.length = (uint16_t)pkt_len;
ret = net_pkt_read(pkt, buff.buffer, pkt_len);
if (ret) {
LOG_ERR("Failed to copy packet to tx buffer: %d", ret);
ret = -ENOBUFS;
goto error;
}
/* Send */
data->tx_done = false;
result = EP_SendFrame(&data->handle, 0, &frame, NULL, NULL);
if (result != kStatus_Success) {
LOG_ERR("Failed to tx frame");
ret = -EIO;
goto error;
}
while (!data->tx_done) {
}
EP_ReclaimTxDescriptor(&data->handle, 0);
if (data->tx_info.status != kNETC_EPTxSuccess) {
LOG_ERR("Failed to tx frame");
ret = -EIO;
goto error;
}
ret = 0;
error:
k_mutex_unlock(&data->tx_mutex);
if (ret != 0) {
eth_stats_update_errors_tx(data->iface);
}
return ret;
}
enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev)
{
ARG_UNUSED(dev);
return (ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T | ETHERNET_LINK_1000BASE_T |
ETHERNET_HW_RX_CHKSUM_OFFLOAD | ETHERNET_HW_FILTERING
#if defined(CONFIG_NET_VLAN)
| ETHERNET_HW_VLAN
#endif
#if defined(CONFIG_NET_PROMISCUOUS_MODE)
| ETHERNET_PROMISC_MODE
#endif
);
}
int netc_eth_set_config(const struct device *dev, enum ethernet_config_type type,
const struct ethernet_config *config)
{
struct netc_eth_data *data = dev->data;
const struct netc_eth_config *cfg = dev->config;
status_t result;
int ret = 0;
switch (type) {
case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
/* Set new Ethernet MAC address and register it with the upper layer */
memcpy(data->mac_addr, config->mac_address.addr, sizeof(data->mac_addr));
result = EP_SetPrimaryMacAddr(&data->handle, (uint8_t *)data->mac_addr);
if (result != kStatus_Success) {
LOG_ERR("PHY device (%p) is not ready, cannot init iface", cfg->phy_dev);
ret = -ENOTSUP;
break;
}
net_if_set_link_addr(data->iface, data->mac_addr, sizeof(data->mac_addr),
NET_LINK_ETHERNET);
LOG_INF("SI%d MAC set to: %02x:%02x:%02x:%02x:%02x:%02x", getSiIdx(cfg->si_idx),
data->mac_addr[0], data->mac_addr[1], data->mac_addr[2], data->mac_addr[3],
data->mac_addr[4], data->mac_addr[5]);
break;
default:
ret = -ENOTSUP;
break;
}
return ret;
}

View file

@ -0,0 +1,121 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_IMX_NETC_PRIV_H_
#define ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_IMX_NETC_PRIV_H_
#include "fsl_netc_endpoint.h"
#include "fsl_msgintr.h"
/* Buffer and descriptor alignment */
#define NETC_BD_ALIGN 128
#define NETC_BUFF_ALIGN 64
#define NETC_RX_RING_BUF_SIZE_ALIGN \
SDK_SIZEALIGN(CONFIG_ETH_NXP_IMX_RX_RING_BUF_SIZE, NETC_BUFF_ALIGN)
/* MSIX definitions */
#define NETC_TX_MSIX_ENTRY_IDX 0
#define NETC_RX_MSIX_ENTRY_IDX 1
#define NETC_MSIX_ENTRY_NUM 2
#define NETC_MSIX_EVENTS_COUNT NETC_MSIX_ENTRY_NUM
#define NETC_TX_INTR_MSG_DATA_START 0
#define NETC_RX_INTR_MSG_DATA_START 16
#define NETC_DRV_MAX_INST_SUPPORT 16
/* MSGINTR */
#define NETC_MSGINTR_CHANNEL 0
#if (CONFIG_ETH_NXP_IMX_MSGINTR == 1)
#define NETC_MSGINTR MSGINTR1
#define NETC_MSGINTR_IRQ MSGINTR1_IRQn
#elif (CONFIG_ETH_NXP_IMX_MSGINTR == 2)
#define NETC_MSGINTR MSGINTR2
#define NETC_MSGINTR_IRQ MSGINTR2_IRQn
#else
#error "Current CONFIG_ETH_NXP_IMX_MSGINTR not support"
#endif
/* Timeout for various operations */
#define NETC_TIMEOUT K_MSEC(20)
/* Helper macros to convert from Zephyr PHY speed to NETC speed/duplex types */
#define PHY_TO_NETC_SPEED(x) \
(PHY_LINK_IS_SPEED_1000M(x) \
? kNETC_MiiSpeed1000M \
: (PHY_LINK_IS_SPEED_100M(x) ? kNETC_MiiSpeed100M : kNETC_MiiSpeed10M))
#define PHY_TO_NETC_DUPLEX_MODE(x) \
(PHY_LINK_IS_FULL_DUPLEX(x) ? kNETC_MiiFullDuplex : kNETC_MiiHalfDuplex)
/* Helper function to generate an Ethernet MAC address for a given ENETC instance */
#define FREESCALE_OUI_B0 0x00
#define FREESCALE_OUI_B1 0x04
#define FREESCALE_OUI_B2 0x9f
#define _NETC_GENERATE_MAC_ADDRESS_RANDOM \
gen_random_mac(mac_addr, FREESCALE_OUI_B0, FREESCALE_OUI_B1, FREESCALE_OUI_B2)
#define _NETC_GENERATE_MAC_ADDRESS_UNIQUE(n) \
do { \
uint32_t id = 0x001100; \
\
mac_addr[0] = FREESCALE_OUI_B0; \
mac_addr[1] = FREESCALE_OUI_B1; \
/* Set MAC address locally administered bit (LAA) */ \
mac_addr[2] = FREESCALE_OUI_B2 | 0x02; \
mac_addr[3] = (id >> 16) & 0xff; \
mac_addr[4] = (id >> 8) & 0xff; \
mac_addr[5] = (id + n) & 0xff; \
} while (0)
#define NETC_GENERATE_MAC_ADDRESS(n) \
static void netc_eth##n##_generate_mac(uint8_t mac_addr[6]) \
{ \
COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \
(_NETC_GENERATE_MAC_ADDRESS_RANDOM), \
(COND_CODE_0(DT_INST_NODE_HAS_PROP(n, local_mac_address), \
(_NETC_GENERATE_MAC_ADDRESS_UNIQUE(n)), \
(ARG_UNUSED(mac_addr))))); \
}
struct netc_eth_config {
uint16_t si_idx;
const struct device *phy_dev;
void (*generate_mac)(uint8_t *mac_addr);
void (*bdr_init)(netc_bdr_config_t *bdr_config, netc_rx_bdr_config_t *rx_bdr_config,
netc_tx_bdr_config_t *tx_bdr_config);
const struct pinctrl_dev_config *pincfg;
uint8_t tx_intr_msg_data;
uint8_t rx_intr_msg_data;
};
typedef uint8_t rx_buffer_t[NETC_RX_RING_BUF_SIZE_ALIGN];
struct netc_eth_data {
ep_handle_t handle;
struct net_if *iface;
uint8_t mac_addr[6];
/* TX */
struct k_mutex tx_mutex;
netc_tx_frame_info_t tx_info;
uint8_t *tx_buff;
volatile bool tx_done;
/* RX */
struct k_sem rx_sem;
struct k_thread rx_thread;
K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_NXP_IMX_RX_THREAD_STACK_SIZE);
uint8_t *rx_frame;
};
int netc_eth_init_common(const struct device *dev);
int netc_eth_tx(const struct device *dev, struct net_pkt *pkt);
enum ethernet_hw_caps netc_eth_get_capabilities(const struct device *dev);
int netc_eth_set_config(const struct device *dev, enum ethernet_config_type type,
const struct ethernet_config *config);
#endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_IMX_NETC_PRIV_H_ */

View file

@ -0,0 +1,193 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_imx_netc_psi
#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(nxp_imx_eth_psi);
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/net/ethernet.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/net_pkt.h>
#include <zephyr/net/phy.h>
#include <ethernet/eth_stats.h>
#include "eth.h"
#include "eth_nxp_imx_netc_priv.h"
static void netc_eth_phylink_callback(const struct device *pdev, struct phy_link_state *state,
void *user_data)
{
const struct device *dev = (struct device *)user_data;
struct netc_eth_data *data = dev->data;
status_t result;
ARG_UNUSED(pdev);
if (state->is_up) {
LOG_DBG("Link up");
result = EP_Up(&data->handle, PHY_TO_NETC_SPEED(state->speed),
PHY_TO_NETC_DUPLEX_MODE(state->speed));
if (result != kStatus_Success) {
LOG_ERR("Failed to set MAC up");
}
net_eth_carrier_on(data->iface);
} else {
LOG_DBG("Link down");
result = EP_Down(&data->handle);
if (result != kStatus_Success) {
LOG_ERR("Failed to set MAC down");
}
net_eth_carrier_off(data->iface);
}
}
static void netc_eth_iface_init(struct net_if *iface)
{
const struct device *dev = net_if_get_device(iface);
struct netc_eth_data *data = dev->data;
const struct netc_eth_config *cfg = dev->config;
status_t result;
/*
* For VLAN, this value is only used to get the correct L2 driver.
* The iface pointer in context should contain the main interface
* if the VLANs are enabled.
*/
if (data->iface == NULL) {
data->iface = iface;
}
/* Set MAC address */
result = EP_SetPrimaryMacAddr(&data->handle, (uint8_t *)data->mac_addr);
if (result != kStatus_Success) {
LOG_ERR("Failed to set MAC address");
}
net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), NET_LINK_ETHERNET);
LOG_INF("SI%d MAC: %02x:%02x:%02x:%02x:%02x:%02x", cfg->si_idx, data->mac_addr[0],
data->mac_addr[1], data->mac_addr[2], data->mac_addr[3], data->mac_addr[4],
data->mac_addr[5]);
ethernet_init(iface);
/*
* PSI controls the PHY. If PHY is configured either as fixed
* link or autoneg, the callback is executed at least once
* immediately after setting it.
*/
if (!device_is_ready(cfg->phy_dev)) {
LOG_ERR("PHY device (%p) is not ready, cannot init iface", cfg->phy_dev);
return;
}
phy_link_callback_set(cfg->phy_dev, &netc_eth_phylink_callback, (void *)dev);
/* Do not start the interface until PHY link is up */
net_if_carrier_off(iface);
}
static int netc_eth_init(const struct device *dev)
{
const struct netc_eth_config *cfg = dev->config;
int err;
err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT);
if (err) {
return err;
}
return netc_eth_init_common(dev);
}
static const struct device *netc_eth_get_phy(const struct device *dev)
{
const struct netc_eth_config *cfg = dev->config;
return cfg->phy_dev;
}
static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_iface_init,
.get_capabilities = netc_eth_get_capabilities,
.get_phy = netc_eth_get_phy,
.set_config = netc_eth_set_config,
.send = netc_eth_tx};
#define NETC_PSI_INSTANCE_DEFINE(n) \
PINCTRL_DT_INST_DEFINE(n); \
NETC_GENERATE_MAC_ADDRESS(n) \
AT_NONCACHEABLE_SECTION_ALIGN( \
static uint8_t eth##n##_tx_buff[CONFIG_ETH_NXP_IMX_TX_RING_BUF_SIZE], \
NETC_BUFF_ALIGN); \
AT_NONCACHEABLE_SECTION_ALIGN( \
static netc_tx_bd_t eth##n##_txbd_array[CONFIG_ETH_NXP_IMX_TX_RING_NUM] \
[CONFIG_ETH_NXP_IMX_TX_RING_LEN], \
NETC_BD_ALIGN); \
static netc_tx_frame_info_t eth##n##_txdirty_array[CONFIG_ETH_NXP_IMX_TX_RING_NUM] \
[CONFIG_ETH_NXP_IMX_TX_RING_LEN]; \
AT_NONCACHEABLE_SECTION_ALIGN( \
static rx_buffer_t eth##n##_rx_buff[CONFIG_ETH_NXP_IMX_RX_RING_NUM] \
[CONFIG_ETH_NXP_IMX_RX_RING_LEN], \
NETC_BUFF_ALIGN); \
static uint64_t eth##n##_rx_buff_addr_array[CONFIG_ETH_NXP_IMX_RX_RING_NUM] \
[CONFIG_ETH_NXP_IMX_RX_RING_LEN]; \
AT_NONCACHEABLE_SECTION(static uint8_t eth##n##_rx_frame[NETC_RX_RING_BUF_SIZE_ALIGN]); \
AT_NONCACHEABLE_SECTION_ALIGN( \
static netc_rx_bd_t eth##n##_rxbd_array[CONFIG_ETH_NXP_IMX_RX_RING_NUM] \
[CONFIG_ETH_NXP_IMX_RX_RING_LEN], \
NETC_BD_ALIGN); \
static void netc_eth##n##_bdr_init(netc_bdr_config_t *bdr_config, \
netc_rx_bdr_config_t *rx_bdr_config, \
netc_tx_bdr_config_t *tx_bdr_config) \
{ \
for (uint8_t ring = 0U; ring < CONFIG_ETH_NXP_IMX_RX_RING_NUM; ring++) { \
for (uint8_t bd = 0U; bd < CONFIG_ETH_NXP_IMX_RX_RING_LEN; bd++) { \
eth##n##_rx_buff_addr_array[ring][bd] = \
(uint64_t)(uintptr_t)&eth##n##_rx_buff[ring][bd]; \
} \
} \
memset(bdr_config, 0, sizeof(netc_bdr_config_t)); \
memset(rx_bdr_config, 0, sizeof(netc_rx_bdr_config_t)); \
memset(tx_bdr_config, 0, sizeof(netc_tx_bdr_config_t)); \
bdr_config->rxBdrConfig = rx_bdr_config; \
bdr_config->txBdrConfig = tx_bdr_config; \
bdr_config->rxBdrConfig[0].bdArray = &eth##n##_rxbd_array[0][0]; \
bdr_config->rxBdrConfig[0].len = CONFIG_ETH_NXP_IMX_RX_RING_LEN; \
bdr_config->rxBdrConfig[0].buffAddrArray = &eth##n##_rx_buff_addr_array[0][0]; \
bdr_config->rxBdrConfig[0].buffSize = NETC_RX_RING_BUF_SIZE_ALIGN; \
bdr_config->rxBdrConfig[0].msixEntryIdx = NETC_RX_MSIX_ENTRY_IDX; \
bdr_config->rxBdrConfig[0].extendDescEn = false; \
bdr_config->rxBdrConfig[0].enThresIntr = true; \
bdr_config->rxBdrConfig[0].enCoalIntr = true; \
bdr_config->rxBdrConfig[0].intrThreshold = 1; \
bdr_config->txBdrConfig[0].bdArray = &eth##n##_txbd_array[0][0]; \
bdr_config->txBdrConfig[0].len = CONFIG_ETH_NXP_IMX_TX_RING_LEN; \
bdr_config->txBdrConfig[0].dirtyArray = &eth##n##_txdirty_array[0][0]; \
bdr_config->txBdrConfig[0].msixEntryIdx = NETC_TX_MSIX_ENTRY_IDX; \
bdr_config->txBdrConfig[0].enIntr = true; \
} \
static struct netc_eth_data netc_eth##n##_data = { \
.mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
.tx_buff = eth##n##_tx_buff, \
.rx_frame = eth##n##_rx_frame, \
}; \
static const struct netc_eth_config netc_eth##n##_config = { \
.generate_mac = netc_eth##n##_generate_mac, \
.bdr_init = netc_eth##n##_bdr_init, \
.phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.si_idx = (DT_INST_PROP(n, mac_index) << 8) | DT_INST_PROP(n, si_index), \
.tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n, \
.rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n, \
}; \
ETH_NET_DEVICE_DT_INST_DEFINE(n, netc_eth_init, NULL, &netc_eth##n##_data, \
&netc_eth##n##_config, CONFIG_ETH_INIT_PRIORITY, \
&netc_eth_api, NET_ETH_MTU);
DT_INST_FOREACH_STATUS_OKAY(NETC_PSI_INSTANCE_DEFINE)

View file

@ -0,0 +1,25 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: NXP i.MX NETC Physical Station Interface (PSI)
compatible: "nxp,imx-netc-psi"
include: [ethernet-controller.yaml, pinctrl-device.yaml]
properties:
reg:
required: true
phy-handle:
required: true
mac-index:
required: true
type: int
description: The MAC index of this PSI.
si-index:
required: true
type: int
description: The SI index of this PSI.