drivers: eth: add support for NXP S32 GMAC
Add initial support for NXP S32 GMAC/EMAC: - it's a copy-implementation with DMA data buffers and buffer descriptors in non-cached memory (buf len and ring size configurable) - PHY interface selection only implemented for S32K3 devices as it is SoC-specific - no PHY driver integration, it works as a fixed link with speed/duplex configured through devicetree - supports multicast hash filtering, promiscuous mode, MAC loopback Signed-off-by: Manuel Argüelles <manuel.arguelles@nxp.com>
This commit is contained in:
parent
e6d6df579a
commit
36f11627ce
7 changed files with 907 additions and 2 deletions
|
@ -40,6 +40,8 @@ if(CONFIG_ETH_NXP_S32_NETC)
|
|||
zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_S32_NETC_VSI_ENABLED eth_nxp_s32_netc_vsi.c)
|
||||
endif()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_ETH_NXP_S32_GMAC eth_nxp_s32_gmac.c)
|
||||
|
||||
if(CONFIG_ETH_NATIVE_POSIX)
|
||||
set(native_posix_source_files eth_native_posix.c eth_native_posix_adapt.c)
|
||||
set_source_files_properties(${native_posix_source_files}
|
||||
|
|
|
@ -56,7 +56,8 @@ source "drivers/ethernet/Kconfig.w5500"
|
|||
source "drivers/ethernet/Kconfig.dsa"
|
||||
source "drivers/ethernet/Kconfig.xlnx_gem"
|
||||
source "drivers/ethernet/Kconfig.cyclonev"
|
||||
source "drivers/ethernet/Kconfig.nxp_s32"
|
||||
source "drivers/ethernet/Kconfig.nxp_s32_netc"
|
||||
source "drivers/ethernet/Kconfig.nxp_s32_gmac"
|
||||
source "drivers/ethernet/Kconfig.smsc91x"
|
||||
source "drivers/ethernet/Kconfig.ivshmem"
|
||||
source "drivers/ethernet/Kconfig.adin2111"
|
||||
|
|
97
drivers/ethernet/Kconfig.nxp_s32_gmac
Normal file
97
drivers/ethernet/Kconfig.nxp_s32_gmac
Normal file
|
@ -0,0 +1,97 @@
|
|||
# Copyright 2022-2023 NXP
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig ETH_NXP_S32_GMAC
|
||||
bool "NXP S32 GMAC driver"
|
||||
default y
|
||||
depends on DT_HAS_NXP_S32_GMAC_ENABLED
|
||||
select NOCACHE_MEMORY
|
||||
select PINCTRL
|
||||
help
|
||||
Enable GMAC/EMAC Ethernet driver for NXP S32 SoCs.
|
||||
|
||||
if ETH_NXP_S32_GMAC
|
||||
|
||||
config ETH_NXP_S32_TX_RING_LEN
|
||||
int "TX ring length"
|
||||
default 4
|
||||
range 4 128
|
||||
help
|
||||
Length of the TX ring. ETH_NXP_S32_TX_RING_BUF_SIZE * ETH_NXP_S32_TX_RING_LEN
|
||||
must be a multiple of TX FIFO block size.
|
||||
|
||||
config ETH_NXP_S32_TX_RING_BUF_SIZE
|
||||
int "TX ring data buffer size"
|
||||
default 1536
|
||||
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 the data bus
|
||||
width.
|
||||
|
||||
config ETH_NXP_S32_RX_RING_LEN
|
||||
int "RX ring length"
|
||||
default 4
|
||||
range 4 128
|
||||
help
|
||||
Length of the RX ring. ETH_NXP_S32_RX_RING_BUF_SIZE * ETH_NXP_S32_RX_RING_LEN
|
||||
must be a multiple of RX FIFO block size.
|
||||
|
||||
config ETH_NXP_S32_RX_RING_BUF_SIZE
|
||||
int "RX ring data buffer size"
|
||||
default 1536
|
||||
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 the data bus
|
||||
width.
|
||||
|
||||
config ETH_NXP_S32_CLOCK_CONFIG_IDX
|
||||
int
|
||||
default 1
|
||||
help
|
||||
This option specifies the zero-based index of the clock configuration
|
||||
used to initialize the GMAC/EMAC clocks.
|
||||
|
||||
config ETH_NXP_S32_RX_THREAD_PRIO
|
||||
int "RX thread priority"
|
||||
default 2
|
||||
help
|
||||
RX thread priority. RX thread is a cooperative thread.
|
||||
|
||||
config ETH_NXP_S32_RX_THREAD_STACK_SIZE
|
||||
int "RX thread stack size"
|
||||
default 1500
|
||||
help
|
||||
RX thread stack size.
|
||||
|
||||
config ETH_NXP_S32_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_S32_LOOPBACK
|
||||
bool "MAC loopback"
|
||||
help
|
||||
MAC operates in loopback mode. The data is looped back through
|
||||
internal FIFO on to the internal MII/GMII interface, passing through
|
||||
the corresponding transmit PHY interface block.
|
||||
This mode requires the MII/GMII Rx clock input signal to function
|
||||
properly because the transmit clock is not internally looped back.
|
||||
|
||||
config ETH_NXP_S32_MULTICAST_FILTER
|
||||
bool "Multicast destination address filtering"
|
||||
help
|
||||
Enable support for multicast destination address filtering in the MAC.
|
||||
MAC performs imperfect filtering using a 64-bit hash table. The upper
|
||||
6-bits CRC of the received multicast address is used as index to the
|
||||
content of the hash table. Only multicast with the computed hash set
|
||||
in the multicast table will be received and all other multicast is
|
||||
dropped by the MAC. If disabled, all multicast is received by the MAC.
|
||||
|
||||
endif # ETH_NXP_S32_GMAC
|
777
drivers/ethernet/eth_nxp_s32_gmac.c
Normal file
777
drivers/ethernet/eth_nxp_s32_gmac.c
Normal file
|
@ -0,0 +1,777 @@
|
|||
/*
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_s32_gmac
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(nxp_s32_eth, CONFIG_ETHERNET_LOG_LEVEL);
|
||||
|
||||
#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 <ethernet/eth_stats.h>
|
||||
#include <soc.h>
|
||||
|
||||
#include <Gmac_Ip.h>
|
||||
#include <Gmac_Ip_Hw_Access.h>
|
||||
#include <Gmac_Ip_Irq.h>
|
||||
#include <Clock_Ip.h>
|
||||
|
||||
#include "eth.h"
|
||||
|
||||
#define ETH_NXP_S32_BUF_TIMEOUT K_MSEC(20)
|
||||
#define ETH_NXP_S32_DMA_TX_TIMEOUT K_MSEC(20)
|
||||
|
||||
#define ETH_NXP_S32_MAC_ADDR_LEN 6U
|
||||
|
||||
#define FREESCALE_OUI_B0 0x00
|
||||
#define FREESCALE_OUI_B1 0x04
|
||||
#define FREESCALE_OUI_B2 0x9f
|
||||
|
||||
struct eth_nxp_s32_config {
|
||||
uint8_t instance;
|
||||
uint8_t tx_ring_idx;
|
||||
uint8_t rx_ring_idx;
|
||||
uint32_t rx_irq;
|
||||
uint32_t tx_irq;
|
||||
void (*do_config)(void);
|
||||
const struct pinctrl_dev_config *pincfg;
|
||||
|
||||
const Gmac_CtrlConfigType ctrl_cfg;
|
||||
GMAC_Type *base;
|
||||
};
|
||||
|
||||
struct eth_nxp_s32_data {
|
||||
struct net_if *iface;
|
||||
uint8_t mac_addr[ETH_NXP_S32_MAC_ADDR_LEN];
|
||||
struct k_mutex tx_mutex;
|
||||
struct k_sem rx_sem;
|
||||
struct k_sem tx_sem;
|
||||
struct k_thread rx_thread;
|
||||
|
||||
K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_NXP_S32_RX_THREAD_STACK_SIZE);
|
||||
};
|
||||
|
||||
static void eth_nxp_s32_rx_thread(void *arg1, void *unused1, void *unused2);
|
||||
|
||||
static inline struct net_if *get_iface(struct eth_nxp_s32_data *ctx, uint16_t vlan_tag)
|
||||
{
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct net_if *iface;
|
||||
|
||||
iface = net_eth_get_vlan_iface(ctx->iface, vlan_tag);
|
||||
if (!iface) {
|
||||
return ctx->iface;
|
||||
}
|
||||
|
||||
return iface;
|
||||
#else
|
||||
ARG_UNUSED(vlan_tag);
|
||||
|
||||
return ctx->iface;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SOC_PART_NUMBER_S32K3)
|
||||
static int select_phy_interface(Gmac_Ip_MiiModeType mode)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
switch (mode) {
|
||||
case GMAC_MII_MODE:
|
||||
regval = DCM_GPR_DCMRWF1_EMAC_CONF_SEL(0U);
|
||||
break;
|
||||
case GMAC_RMII_MODE:
|
||||
regval = DCM_GPR_DCMRWF1_EMAC_CONF_SEL(2U);
|
||||
break;
|
||||
#if (FEATURE_GMAC_RGMII_EN == 1U)
|
||||
case GMAC_RGMII_MODE:
|
||||
regval = DCM_GPR_DCMRWF1_EMAC_CONF_SEL(1U);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IP_DCM_GPR->DCMRWF1 = (IP_DCM_GPR->DCMRWF1 & ~DCM_GPR_DCMRWF1_EMAC_CONF_SEL_MASK) | regval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error "SoC not supported"
|
||||
#endif /* CONFIG_SOC_PART_NUMBER_S32K3 */
|
||||
|
||||
static int eth_nxp_s32_init(const struct device *dev)
|
||||
{
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
Gmac_Ip_StatusType mac_status;
|
||||
Clock_Ip_StatusType clk_status;
|
||||
int err;
|
||||
|
||||
err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently, clock control shim driver does not support configuring clock
|
||||
* muxes individually, so use the HAL directly.
|
||||
*/
|
||||
clk_status = Clock_Ip_Init(&Clock_Ip_aClockConfig[CONFIG_ETH_NXP_S32_CLOCK_CONFIG_IDX]);
|
||||
if (clk_status != CLOCK_IP_SUCCESS) {
|
||||
LOG_ERR("Failed to configure clocks (%d)", clk_status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* PHY mode selection must be done before the controller is reset,
|
||||
* because the interface type is latched at controller's reset
|
||||
*/
|
||||
err = select_phy_interface(cfg->ctrl_cfg.Gmac_pCtrlConfig->MiiMode);
|
||||
if (err != 0) {
|
||||
LOG_ERR("Failed to select PHY interface (%d)", err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
mac_status = Gmac_Ip_Init(cfg->instance, &cfg->ctrl_cfg);
|
||||
if (mac_status != GMAC_STATUS_SUCCESS) {
|
||||
LOG_ERR("Failed to initialize GMAC%d (%d)", cfg->instance, mac_status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_mutex_init(&ctx->tx_mutex);
|
||||
k_sem_init(&ctx->rx_sem, 0, 1);
|
||||
k_sem_init(&ctx->tx_sem, 0, 1);
|
||||
|
||||
k_thread_create(&ctx->rx_thread, ctx->rx_thread_stack,
|
||||
K_KERNEL_STACK_SIZEOF(ctx->rx_thread_stack),
|
||||
eth_nxp_s32_rx_thread, (void *)dev, NULL, NULL,
|
||||
K_PRIO_COOP(CONFIG_ETH_NXP_S32_RX_THREAD_PRIO),
|
||||
0, K_NO_WAIT);
|
||||
k_thread_name_set(&ctx->rx_thread, "eth_nxp_s32_rx");
|
||||
|
||||
if (cfg->do_config != NULL) {
|
||||
cfg->do_config();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eth_nxp_s32_start(const struct device *dev)
|
||||
{
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
|
||||
Gmac_Ip_EnableController(cfg->instance);
|
||||
|
||||
irq_enable(cfg->rx_irq);
|
||||
irq_enable(cfg->tx_irq);
|
||||
|
||||
LOG_DBG("GMAC%d started", cfg->instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eth_nxp_s32_stop(const struct device *dev)
|
||||
{
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
Gmac_Ip_StatusType status;
|
||||
int err = 0;
|
||||
|
||||
irq_enable(cfg->rx_irq);
|
||||
irq_enable(cfg->tx_irq);
|
||||
|
||||
status = Gmac_Ip_DisableController(cfg->instance);
|
||||
if (status != GMAC_STATUS_SUCCESS) {
|
||||
LOG_ERR("Failed to disable controller GMAC%d (%d)", cfg->instance, status);
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
LOG_DBG("GMAC%d stopped", cfg->instance);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(ETH_NXP_S32_MULTICAST_FILTER)
|
||||
static void eth_nxp_s32_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined)
|
||||
{
|
||||
const struct device *dev = net_if_get_device(iface);
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
struct net_eth_addr mac_addr;
|
||||
|
||||
switch (addr->family) {
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
case AF_INET:
|
||||
net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr);
|
||||
break;
|
||||
#endif /* CONFIG_NET_IPV4 */
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
case AF_INET6:
|
||||
net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr);
|
||||
break;
|
||||
#endif /* CONFIG_NET_IPV6 */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_joined) {
|
||||
Gmac_Ip_AddDstAddrToHashFilter(cfg->instance, mac_addr.addr);
|
||||
} else {
|
||||
Gmac_Ip_RemoveDstAddrFromHashFilter(cfg->instance, mac_addr.addr);
|
||||
}
|
||||
}
|
||||
#endif /* ETH_NXP_S32_MULTICAST_FILTER */
|
||||
|
||||
static void eth_nxp_s32_iface_init(struct net_if *iface)
|
||||
{
|
||||
const struct device *dev = net_if_get_device(iface);
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
#if defined(ETH_NXP_S32_MULTICAST_FILTER)
|
||||
static struct net_if_mcast_monitor mon;
|
||||
|
||||
net_if_mcast_mon_register(&mon, iface, eth_nxp_s32_mcast_cb);
|
||||
#endif /* ETH_NXP_S32_MULTICAST_FILTER */
|
||||
|
||||
/* 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 (ctx->iface == NULL) {
|
||||
ctx->iface = iface;
|
||||
}
|
||||
|
||||
ethernet_init(iface);
|
||||
|
||||
net_if_set_link_addr(iface, ctx->mac_addr, sizeof(ctx->mac_addr), NET_LINK_ETHERNET);
|
||||
LOG_INF("GMAC%d MAC address %02x:%02x:%02x:%02x:%02x:%02x", cfg->instance,
|
||||
ctx->mac_addr[0], ctx->mac_addr[1], ctx->mac_addr[2],
|
||||
ctx->mac_addr[3], ctx->mac_addr[4], ctx->mac_addr[5]);
|
||||
|
||||
/* No PHY available, link is always up and MAC speed/duplex settings are fixed */
|
||||
net_eth_carrier_on(ctx->iface);
|
||||
}
|
||||
|
||||
static int eth_nxp_s32_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
{
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
size_t pkt_len = net_pkt_get_len(pkt);
|
||||
int res = 0;
|
||||
Gmac_Ip_BufferType buf;
|
||||
Gmac_Ip_TxInfoType tx_info;
|
||||
Gmac_Ip_StatusType status;
|
||||
Gmac_Ip_TxOptionsType tx_options = {
|
||||
.NoInt = FALSE,
|
||||
.CrcPadIns = GMAC_CRC_AND_PAD_INSERTION,
|
||||
.ChecksumIns = GMAC_CHECKSUM_INSERTION_PROTO_PSEUDOH
|
||||
};
|
||||
|
||||
__ASSERT(pkt, "Packet pointer is NULL");
|
||||
|
||||
k_mutex_lock(&ctx->tx_mutex, K_FOREVER);
|
||||
k_sem_reset(&ctx->tx_sem);
|
||||
|
||||
buf.Length = (uint16_t)pkt_len;
|
||||
buf.Data = NULL;
|
||||
status = Gmac_Ip_GetTxBuff(cfg->instance, cfg->tx_ring_idx, &buf, NULL);
|
||||
if (status != GMAC_STATUS_SUCCESS) {
|
||||
LOG_ERR("Failed to get tx buffer (%d)", status);
|
||||
res = -ENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
res = net_pkt_read(pkt, buf.Data, pkt_len);
|
||||
if (res) {
|
||||
LOG_ERR("Failed to copy packet to tx buffer (%d)", res);
|
||||
res = -ENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buf.Length = (uint16_t)pkt_len;
|
||||
status = Gmac_Ip_SendFrame(cfg->instance, cfg->tx_ring_idx, &buf, &tx_options);
|
||||
if (status != GMAC_STATUS_SUCCESS) {
|
||||
LOG_ERR("Failed to tx frame (%d)", status);
|
||||
res = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Wait for the transmission to complete */
|
||||
if (k_sem_take(&ctx->tx_sem, ETH_NXP_S32_DMA_TX_TIMEOUT) != 0) {
|
||||
LOG_ERR("Timeout transmitting frame");
|
||||
res = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Restore the buffer address pointer and clear the descriptor after the status is read */
|
||||
status = Gmac_Ip_GetTransmitStatus(cfg->instance, cfg->tx_ring_idx, &buf, &tx_info);
|
||||
if (status != GMAC_STATUS_SUCCESS) {
|
||||
LOG_ERR("Failed to restore tx buffer: %s (%d) ",
|
||||
(status == GMAC_STATUS_BUSY ? "busy" : "buf not found"), status);
|
||||
res = -EIO;
|
||||
} else if (tx_info.ErrMask != 0U) {
|
||||
LOG_ERR("Tx frame has errors (error mask 0x%X)", tx_info.ErrMask);
|
||||
res = -EIO;
|
||||
}
|
||||
|
||||
error:
|
||||
k_mutex_unlock(&ctx->tx_mutex);
|
||||
|
||||
if (res != 0) {
|
||||
eth_stats_update_errors_tx(ctx->iface);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct net_pkt *eth_nxp_s32_get_pkt(const struct device *dev,
|
||||
Gmac_Ip_BufferType *buf,
|
||||
Gmac_Ip_RxInfoType *rx_info,
|
||||
uint16_t *vlan_tag)
|
||||
{
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
struct net_pkt *pkt = NULL;
|
||||
int res = 0;
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct net_eth_hdr *hdr;
|
||||
struct net_eth_vlan_hdr *hdr_vlan;
|
||||
#if CONFIG_NET_TC_RX_COUNT > 1
|
||||
enum net_priority prio;
|
||||
#endif /* CONFIG_NET_TC_RX_COUNT > 1 */
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
|
||||
/* Using root iface, it will be updated in net_recv_data() */
|
||||
pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, rx_info->PktLen,
|
||||
AF_UNSPEC, 0, ETH_NXP_S32_BUF_TIMEOUT);
|
||||
if (!pkt) {
|
||||
LOG_ERR("Failed to allocate rx buffer of length %u", rx_info->PktLen);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
res = net_pkt_write(pkt, buf->Data, rx_info->PktLen);
|
||||
if (res) {
|
||||
LOG_ERR("Failed to write rx frame into pkt buffer (%d)", res);
|
||||
net_pkt_unref(pkt);
|
||||
pkt = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
hdr = NET_ETH_HDR(pkt);
|
||||
if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) {
|
||||
hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt);
|
||||
net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci));
|
||||
*vlan_tag = net_pkt_vlan_tag(pkt);
|
||||
|
||||
#if CONFIG_NET_TC_RX_COUNT > 1
|
||||
prio = net_vlan2priority(net_pkt_vlan_priority(pkt));
|
||||
net_pkt_set_priority(pkt, prio);
|
||||
#endif /* CONFIG_NET_TC_RX_COUNT > 1 */
|
||||
}
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
|
||||
exit:
|
||||
if (!pkt) {
|
||||
eth_stats_update_errors_rx(get_iface(ctx, *vlan_tag));
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void eth_nxp_s32_rx(const struct device *dev)
|
||||
{
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
|
||||
struct net_pkt *pkt;
|
||||
int res = 0;
|
||||
Gmac_Ip_RxInfoType rx_info = {0};
|
||||
Gmac_Ip_BufferType buf;
|
||||
Gmac_Ip_StatusType status;
|
||||
|
||||
status = Gmac_Ip_ReadFrame(cfg->instance, cfg->rx_ring_idx, &buf, &rx_info);
|
||||
if (rx_info.ErrMask != 0U) {
|
||||
Gmac_Ip_ProvideRxBuff(cfg->instance, cfg->rx_ring_idx, &buf);
|
||||
LOG_ERR("Rx frame has errors (error mask 0x%X)", rx_info.ErrMask);
|
||||
} else if (status == GMAC_STATUS_SUCCESS) {
|
||||
pkt = eth_nxp_s32_get_pkt(dev, &buf, &rx_info, &vlan_tag);
|
||||
Gmac_Ip_ProvideRxBuff(cfg->instance, cfg->rx_ring_idx, &buf);
|
||||
if (pkt != NULL) {
|
||||
res = net_recv_data(get_iface(ctx, vlan_tag), pkt);
|
||||
if (res < 0) {
|
||||
eth_stats_update_errors_rx(get_iface(ctx, vlan_tag));
|
||||
net_pkt_unref(pkt);
|
||||
LOG_ERR("Failed to enqueue frame into rx queue (%d)", res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eth_nxp_s32_rx_thread(void *arg1, void *unused1, void *unused2)
|
||||
{
|
||||
const struct device *dev = (const struct device *)arg1;
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
int res;
|
||||
int work;
|
||||
|
||||
ARG_UNUSED(unused1);
|
||||
ARG_UNUSED(unused2);
|
||||
__ASSERT_NO_MSG(arg1 != NULL);
|
||||
__ASSERT_NO_MSG(ctx != NULL);
|
||||
|
||||
while (1) {
|
||||
res = k_sem_take(&ctx->rx_sem, K_FOREVER);
|
||||
__ASSERT_NO_MSG(res == 0);
|
||||
|
||||
work = 0;
|
||||
while (Gmac_Ip_IsFrameAvailable(cfg->instance, cfg->rx_ring_idx)) {
|
||||
eth_nxp_s32_rx(dev);
|
||||
if (++work == CONFIG_ETH_NXP_S32_RX_BUDGET) {
|
||||
/* More work to do, reschedule */
|
||||
work = 0;
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
/* All work done, re-enable rx interrupt and exit polling */
|
||||
irq_enable(cfg->rx_irq);
|
||||
|
||||
/* In case a frame arrived after last eth_nxp_s32_rx() and before irq_enable() */
|
||||
if (Gmac_Ip_IsFrameAvailable(cfg->instance, cfg->rx_ring_idx)) {
|
||||
eth_nxp_s32_rx(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int eth_nxp_s32_set_config(const struct device *dev,
|
||||
enum ethernet_config_type type,
|
||||
const struct ethernet_config *config)
|
||||
{
|
||||
struct eth_nxp_s32_data *ctx = dev->data;
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
int res = 0;
|
||||
uint32_t regval;
|
||||
|
||||
ARG_UNUSED(cfg);
|
||||
ARG_UNUSED(regval);
|
||||
|
||||
switch (type) {
|
||||
case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
|
||||
/* Set new Ethernet MAC address and register it with the upper layer */
|
||||
memcpy(ctx->mac_addr, config->mac_address.addr, sizeof(ctx->mac_addr));
|
||||
Gmac_Ip_SetMacAddr(cfg->instance, (const uint8_t *)ctx->mac_addr);
|
||||
net_if_set_link_addr(ctx->iface, ctx->mac_addr, sizeof(ctx->mac_addr),
|
||||
NET_LINK_ETHERNET);
|
||||
LOG_INF("MAC set to: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ctx->mac_addr[0], ctx->mac_addr[1], ctx->mac_addr[2],
|
||||
ctx->mac_addr[3], ctx->mac_addr[4], ctx->mac_addr[5]);
|
||||
break;
|
||||
#if defined(CONFIG_NET_PROMISCUOUS_MODE)
|
||||
case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
|
||||
regval = cfg->base->MAC_PACKET_FILTER;
|
||||
if (config->promisc_mode && !(regval & GMAC_MAC_PACKET_FILTER_PR_MASK)) {
|
||||
cfg->base->MAC_PACKET_FILTER |= GMAC_MAC_PACKET_FILTER_PR_MASK;
|
||||
} else if (!config->promisc_mode && (regval & GMAC_MAC_PACKET_FILTER_PR_MASK)) {
|
||||
cfg->base->MAC_PACKET_FILTER &= ~GMAC_MAC_PACKET_FILTER_PR_MASK;
|
||||
} else {
|
||||
res = -EALREADY;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
res = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static enum ethernet_hw_caps eth_nxp_s32_get_capabilities(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return (ETHERNET_LINK_10BASE_T
|
||||
| ETHERNET_LINK_100BASE_T
|
||||
#if (FEATURE_GMAC_RGMII_EN == 1U)
|
||||
| ETHERNET_LINK_1000BASE_T
|
||||
#endif
|
||||
| ETHERNET_DUPLEX_SET
|
||||
| ETHERNET_HW_TX_CHKSUM_OFFLOAD
|
||||
| ETHERNET_HW_RX_CHKSUM_OFFLOAD
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
| ETHERNET_HW_VLAN
|
||||
#endif
|
||||
#if defined(CONFIG_NET_PROMISCUOUS_MODE)
|
||||
| ETHERNET_PROMISC_MODE
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
static void eth_nxp_s32_tx_irq(const struct device *dev)
|
||||
{
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
|
||||
GMAC_TxIRQHandler(cfg->instance, cfg->tx_ring_idx);
|
||||
}
|
||||
|
||||
static void eth_nxp_s32_rx_irq(const struct device *dev)
|
||||
{
|
||||
const struct eth_nxp_s32_config *cfg = dev->config;
|
||||
|
||||
GMAC_RxIRQHandler(cfg->instance, cfg->rx_ring_idx);
|
||||
}
|
||||
|
||||
static const struct ethernet_api eth_api = {
|
||||
.iface_api.init = eth_nxp_s32_iface_init,
|
||||
.get_capabilities = eth_nxp_s32_get_capabilities,
|
||||
.start = eth_nxp_s32_start,
|
||||
.stop = eth_nxp_s32_stop,
|
||||
.send = eth_nxp_s32_tx,
|
||||
.set_config = eth_nxp_s32_set_config,
|
||||
};
|
||||
|
||||
|
||||
BUILD_ASSERT(((CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE * CONFIG_ETH_NXP_S32_RX_RING_LEN)
|
||||
% FEATURE_GMAC_MTL_RX_FIFO_BLOCK_SIZE) == 0,
|
||||
"CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE * CONFIG_ETH_NXP_S32_RX_RING_LEN "
|
||||
"must be multiple of RX FIFO block size");
|
||||
BUILD_ASSERT(((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE * CONFIG_ETH_NXP_S32_TX_RING_LEN)
|
||||
% FEATURE_GMAC_MTL_TX_FIFO_BLOCK_SIZE) == 0,
|
||||
"CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE * CONFIG_ETH_NXP_S32_TX_RING_LEN "
|
||||
"must be multiple of TX FIFO block size");
|
||||
BUILD_ASSERT((CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_BYTES) == 0,
|
||||
"CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE must be multiple of the data bus width");
|
||||
BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_BYTES) == 0,
|
||||
"CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE must be multiple of the data bus width");
|
||||
|
||||
#define ETH_NXP_S32_FIXED_LINK_NODE(n) \
|
||||
DT_INST_CHILD(n, fixed_link)
|
||||
|
||||
#define ETH_NXP_S32_IS_FIXED_LINK(n) \
|
||||
DT_NODE_EXISTS(ETH_NXP_S32_FIXED_LINK_NODE(n))
|
||||
|
||||
#define ETH_NXP_S32_FIXED_LINK_SPEED(n) \
|
||||
DT_PROP(ETH_NXP_S32_FIXED_LINK_NODE(n), speed)
|
||||
|
||||
#define ETH_NXP_S32_FIXED_LINK_FULL_DUPLEX(n) \
|
||||
DT_PROP(ETH_NXP_S32_FIXED_LINK_NODE(n), full_duplex)
|
||||
|
||||
#define ETH_NXP_S32_MAC_SPEED(n) \
|
||||
COND_CODE_1(ETH_NXP_S32_IS_FIXED_LINK(n), \
|
||||
(CONCAT(CONCAT(GMAC_SPEED_, ETH_NXP_S32_FIXED_LINK_SPEED(n)), M)), \
|
||||
(GMAC_SPEED_100M))
|
||||
|
||||
#define ETH_NXP_S32_MAC_DUPLEX(n) \
|
||||
COND_CODE_1(ETH_NXP_S32_IS_FIXED_LINK(n), \
|
||||
(COND_CODE_1(ETH_NXP_S32_FIXED_LINK_FULL_DUPLEX(n), \
|
||||
(GMAC_FULL_DUPLEX), (GMAC_HALF_DUPLEX))), \
|
||||
(GMAC_FULL_DUPLEX))
|
||||
|
||||
#define ETH_NXP_S32_MAC_MII(n) \
|
||||
CONCAT(CONCAT(GMAC_, DT_INST_STRING_UPPER_TOKEN(n, phy_connection_type)), _MODE)
|
||||
|
||||
#define ETH_NXP_S32_IRQ_INIT(n, name) \
|
||||
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, name, irq), \
|
||||
DT_INST_IRQ_BY_NAME(n, name, priority), \
|
||||
eth_nxp_s32_##name##_irq, \
|
||||
DEVICE_DT_INST_GET(n), \
|
||||
COND_CODE_1(DT_INST_IRQ_HAS_CELL(n, flags), \
|
||||
(DT_INST_IRQ_BY_NAME(n, name, flags)), (0)));
|
||||
|
||||
#define ETH_NXP_S32_INIT_CONFIG(n) \
|
||||
static void eth_nxp_s32_init_config_##n(void) \
|
||||
{ \
|
||||
const struct device *dev = DEVICE_DT_INST_GET(n); \
|
||||
struct eth_nxp_s32_data *ctx = dev->data; \
|
||||
const struct eth_nxp_s32_config *cfg = dev->config; \
|
||||
\
|
||||
ETH_NXP_S32_IRQ_INIT(n, tx); \
|
||||
ETH_NXP_S32_IRQ_INIT(n, rx); \
|
||||
\
|
||||
COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), ( \
|
||||
gen_random_mac(ctx->mac_addr, FREESCALE_OUI_B0, \
|
||||
FREESCALE_OUI_B1, FREESCALE_OUI_B2); \
|
||||
Gmac_Ip_SetMacAddr(cfg->instance, ctx->mac_addr); \
|
||||
), ( \
|
||||
Gmac_Ip_GetMacAddr(cfg->instance, ctx->mac_addr); \
|
||||
)) \
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_RX_CALLBACK(n) \
|
||||
static void eth_nxp_s32_rx_callback_##n(uint8_t inst, uint8_t chan) \
|
||||
{ \
|
||||
const struct device *dev = DEVICE_DT_INST_GET(n); \
|
||||
struct eth_nxp_s32_data *ctx = dev->data; \
|
||||
const struct eth_nxp_s32_config *cfg = dev->config; \
|
||||
\
|
||||
ARG_UNUSED(inst); \
|
||||
ARG_UNUSED(chan); \
|
||||
\
|
||||
/* Rx irq will be re-enabled from Rx thread */ \
|
||||
irq_disable(cfg->rx_irq); \
|
||||
k_sem_give(&ctx->rx_sem); \
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_TX_CALLBACK(n) \
|
||||
static void eth_nxp_s32_tx_callback_##n(uint8_t inst, uint8_t chan) \
|
||||
{ \
|
||||
const struct device *dev = DEVICE_DT_INST_GET(n); \
|
||||
struct eth_nxp_s32_data *ctx = dev->data; \
|
||||
\
|
||||
ARG_UNUSED(inst); \
|
||||
ARG_UNUSED(chan); \
|
||||
\
|
||||
k_sem_give(&ctx->tx_sem); \
|
||||
}
|
||||
|
||||
#define _ETH_NXP_S32_RING(n, name, len, buf_size) \
|
||||
static Gmac_Ip_BufferDescriptorType eth_nxp_s32_##name##ring_desc_##n[len] \
|
||||
__nocache __aligned(FEATURE_GMAC_BUFFDESCR_ALIGNMENT_BYTES); \
|
||||
static uint8_t eth_nxp_s32_##name##ring_buf_##n[len * buf_size] \
|
||||
__nocache __aligned(FEATURE_GMAC_BUFF_ALIGNMENT_BYTES)
|
||||
|
||||
#define ETH_NXP_S32_RX_RING(n) \
|
||||
_ETH_NXP_S32_RING(n, rx, \
|
||||
CONFIG_ETH_NXP_S32_RX_RING_LEN, \
|
||||
CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE)
|
||||
|
||||
#define ETH_NXP_S32_TX_RING(n) \
|
||||
_ETH_NXP_S32_RING(n, tx, \
|
||||
CONFIG_ETH_NXP_S32_TX_RING_LEN, \
|
||||
CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE)
|
||||
|
||||
#define ETH_NXP_S32_MAC_TXTIMESHAPER_CONFIG(n) \
|
||||
static const Gmac_Ip_TxTimeAwareShaper eth_nxp_s32_mac_txtimeshaper_config_##n = {\
|
||||
.GateControlList = NULL, \
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_MAC_RXRING_CONFIG(n) \
|
||||
static const Gmac_Ip_RxRingConfigType eth_nxp_s32_mac_rxring_config_##n = { \
|
||||
.RingDesc = eth_nxp_s32_rxring_desc_##n, \
|
||||
.Callback = eth_nxp_s32_rx_callback_##n, \
|
||||
.Buffer = eth_nxp_s32_rxring_buf_##n, \
|
||||
.Interrupts = (uint32_t)GMAC_CH_INTERRUPT_RI, \
|
||||
.BufferLen = CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE, \
|
||||
.RingSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, \
|
||||
.PriorityMask = 0U, \
|
||||
.DmaBurstLength = 32U, \
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_MAC_TXRING_CONFIG(n) \
|
||||
static const Gmac_Ip_TxRingConfigType eth_nxp_s32_mac_txring_config_##n = { \
|
||||
.Weight = 0U, \
|
||||
.IdleSlopeCredit = 0U, \
|
||||
.SendSlopeCredit = 0U, \
|
||||
.HiCredit = 0U, \
|
||||
.LoCredit = 0, \
|
||||
.RingDesc = eth_nxp_s32_txring_desc_##n, \
|
||||
.Callback = eth_nxp_s32_tx_callback_##n, \
|
||||
.Buffer = eth_nxp_s32_txring_buf_##n, \
|
||||
.Interrupts = (uint32_t)GMAC_CH_INTERRUPT_TI, \
|
||||
.BufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \
|
||||
.RingSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, \
|
||||
.PriorityMask = 0U, \
|
||||
.DmaBurstLength = 32U, \
|
||||
.QueueOpMode = GMAC_OP_MODE_DCB_GEN, \
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_MAC_PKT_FILTER(n) \
|
||||
((uint32_t)(0U \
|
||||
COND_CODE_1(CONFIG_ETH_NXP_S32_MULTICAST_FILTER, \
|
||||
(|GMAC_PKT_FILTER_HASH_MULTICAST), \
|
||||
(|GMAC_PKT_FILTER_PASS_ALL_MULTICAST)) \
|
||||
))
|
||||
|
||||
#define ETH_NXP_S32_MAC_CONF(n) \
|
||||
((uint32_t)(GMAC_MAC_CONFIG_CRC_STRIPPING \
|
||||
| GMAC_MAC_CONFIG_AUTO_PAD \
|
||||
| GMAC_MAC_CONFIG_CHECKSUM_OFFLOAD \
|
||||
IF_ENABLED(CONFIG_ETH_NXP_S32_LOOPBACK, \
|
||||
(|GMAC_MAC_CONFIG_LOOPBACK)) \
|
||||
))
|
||||
|
||||
#define ETH_NXP_S32_MAC_CONFIG(n) \
|
||||
static const Gmac_Ip_ConfigType eth_nxp_s32_mac_config_##n = { \
|
||||
.RxRingCount = 1U, \
|
||||
.TxRingCount = 1U, \
|
||||
.Interrupts = 0U, \
|
||||
.Callback = NULL, \
|
||||
.TxSchedAlgo = GMAC_SCHED_ALGO_SP, \
|
||||
.MiiMode = ETH_NXP_S32_MAC_MII(n), \
|
||||
.Speed = ETH_NXP_S32_MAC_SPEED(n), \
|
||||
.Duplex = ETH_NXP_S32_MAC_DUPLEX(n), \
|
||||
.MacConfig = ETH_NXP_S32_MAC_CONF(n), \
|
||||
.MacPktFilterConfig = ETH_NXP_S32_MAC_PKT_FILTER(n), \
|
||||
.EnableCtrl = false, \
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_MAC_ADDR(n) \
|
||||
BUILD_ASSERT(DT_INST_PROP(n, zephyr_random_mac_address) || \
|
||||
NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)), \
|
||||
"eth_nxp_s32_gmac requires either a fixed or random MAC address"); \
|
||||
static const uint8_t eth_nxp_s32_mac_addr_##n[ETH_NXP_S32_MAC_ADDR_LEN] = \
|
||||
DT_INST_PROP_OR(n, local_mac_address, {0U})
|
||||
|
||||
#define ETH_NXP_S32_MAC_STATE(n) Gmac_Ip_StateType eth_nxp_s32_mac_state_##n
|
||||
|
||||
#define ETH_NXP_S32_CTRL_CONFIG(n) \
|
||||
{ \
|
||||
.Gmac_pCtrlState = ð_nxp_s32_mac_state_##n, \
|
||||
.Gmac_pCtrlConfig = ð_nxp_s32_mac_config_##n, \
|
||||
.Gmac_paCtrlRxRingConfig = ð_nxp_s32_mac_rxring_config_##n, \
|
||||
.Gmac_paCtrlTxRingConfig = ð_nxp_s32_mac_txring_config_##n, \
|
||||
.Gmac_pau8CtrlPhysAddr = ð_nxp_s32_mac_addr_##n[0], \
|
||||
.Gmac_pCtrlTxTimeAwareShaper = ð_nxp_s32_mac_txtimeshaper_config_##n,\
|
||||
}
|
||||
|
||||
#define ETH_NXP_S32_HW_INSTANCE_CHECK(i, n) \
|
||||
((DT_INST_REG_ADDR(n) == IP_GMAC_##i##_BASE) ? i : 0)
|
||||
|
||||
#define ETH_NXP_S32_HW_INSTANCE(n) \
|
||||
LISTIFY(__DEBRACKET FEATURE_GMAC_NUM_INSTANCES, \
|
||||
ETH_NXP_S32_HW_INSTANCE_CHECK, (|), n)
|
||||
|
||||
#define ETH_NXP_S32_DEVICE(n) \
|
||||
ETH_NXP_S32_TX_CALLBACK(n) \
|
||||
ETH_NXP_S32_RX_CALLBACK(n) \
|
||||
ETH_NXP_S32_INIT_CONFIG(n) \
|
||||
ETH_NXP_S32_RX_RING(n); \
|
||||
ETH_NXP_S32_TX_RING(n); \
|
||||
ETH_NXP_S32_MAC_STATE(n); \
|
||||
ETH_NXP_S32_MAC_TXTIMESHAPER_CONFIG(n); \
|
||||
ETH_NXP_S32_MAC_RXRING_CONFIG(n); \
|
||||
ETH_NXP_S32_MAC_TXRING_CONFIG(n); \
|
||||
ETH_NXP_S32_MAC_CONFIG(n); \
|
||||
ETH_NXP_S32_MAC_ADDR(n); \
|
||||
PINCTRL_DT_INST_DEFINE(n); \
|
||||
\
|
||||
static const struct eth_nxp_s32_config eth_nxp_s32_config_##n = { \
|
||||
.instance = ETH_NXP_S32_HW_INSTANCE(n), \
|
||||
.base = (GMAC_Type *)DT_INST_REG_ADDR(n), \
|
||||
.ctrl_cfg = ETH_NXP_S32_CTRL_CONFIG(n), \
|
||||
.do_config = eth_nxp_s32_init_config_##n, \
|
||||
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||
.rx_irq = DT_INST_IRQ_BY_NAME(n, rx, irq), \
|
||||
.tx_irq = DT_INST_IRQ_BY_NAME(n, tx, irq), \
|
||||
.tx_ring_idx = 0U, \
|
||||
.rx_ring_idx = 0U, \
|
||||
}; \
|
||||
\
|
||||
static struct eth_nxp_s32_data eth_nxp_s32_data_##n; \
|
||||
\
|
||||
ETH_NET_DEVICE_DT_INST_DEFINE(n, \
|
||||
eth_nxp_s32_init, \
|
||||
NULL, \
|
||||
ð_nxp_s32_data_##n, \
|
||||
ð_nxp_s32_config_##n, \
|
||||
CONFIG_ETH_INIT_PRIORITY, \
|
||||
ð_api, \
|
||||
NET_ETH_MTU);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(ETH_NXP_S32_DEVICE)
|
28
dts/bindings/ethernet/nxp,s32-gmac.yaml
Normal file
28
dts/bindings/ethernet/nxp,s32-gmac.yaml
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2023 NXP
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: NXP S32 GMAC/EMAC driver
|
||||
|
||||
compatible: "nxp,s32-gmac"
|
||||
|
||||
include: [ethernet-controller.yaml, "ethernet,fixed-link.yaml", pinctrl-device.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
interrupts:
|
||||
required: true
|
||||
|
||||
interrupt-names:
|
||||
required: true
|
||||
|
||||
phy-connection-type:
|
||||
type: string
|
||||
enum:
|
||||
- "mii"
|
||||
- "rmii"
|
||||
- "rgmii"
|
||||
description: |
|
||||
Specifies interface type between the Ethernet device and a physical
|
||||
layer (PHY) device.
|
2
west.yml
2
west.yml
|
@ -188,7 +188,7 @@ manifest:
|
|||
groups:
|
||||
- hal
|
||||
- name: hal_nxp
|
||||
revision: 1a55ccfde649a97df74a8853cbd9787ddd34bfc4
|
||||
revision: 674aa3834a60720adab03b2ba70c8b4db90f4916
|
||||
path: modules/hal/nxp
|
||||
groups:
|
||||
- hal
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue