MCUXpresso_MIMXRT1021xxxxx/boards/evkmimxrt1020/azure_rtos_examples/azure_iot_embedded_sdk/nx_driver_imxrt.c
2022-08-23 23:00:33 +08:00

2893 lines
140 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** NetX Component */
/** */
/** Ethernet device driver for IMX family micro processors */
/** */
/**************************************************************************/
/**************************************************************************/
/* Indicate that driver source is being compiled. */
#define NX_DRIVER_SOURCE
/****** DRIVER SPECIFIC ****** Start of part/vendor specific include area. Include driver-specific include file here! */
//#ifndef NX_DRIVER_IMXRT1052_H
/* Determine if the driver uses IP deferred processing or direct ISR processing. */
#define NX_DRIVER_ENABLE_DEFERRED /* Define this to enable deferred ISR processing. */
/* #define ENET_ENHANCEDBUFFERDESCRIPTOR_MODE*/
/* Determine if the packet transmit queue logic is required for this driver. */
/* No, not required for this driver. #define NX_DIRVER_INTERNAL_TRANSMIT_QUEUE */
/* Include driver specific include file. */
#include "fsl_common.h"
#include "fsl_enet.h"
#include "fsl_phy.h"
#include "fsl_enet_mdio.h"
#include "fsl_debug_console.h"
#include "nx_driver_imxrt.h"
#ifndef BOARD_NETWORK_USE_100M_ENET_PORT
#define BOARD_NETWORK_USE_100M_ENET_PORT 1
#endif
#if defined(BOARD_NETWORK_USE_100M_ENET_PORT) && (BOARD_NETWORK_USE_100M_ENET_PORT == 1)
#include "fsl_phyksz8081.h"
#else
#include "fsl_phyrtl8211f.h"
#endif
//#endif
/****** DRIVER SPECIFIC ****** End of part/vendor specific include file area! */
#if defined(BOARD_NETWORK_USE_100M_ENET_PORT) && (BOARD_NETWORK_USE_100M_ENET_PORT == 1)
#define EXAMPLE_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS
#define EXAMPLE_ENET ENET
/* PHY operations. */
#define EXAMPLE_PHY_OPS phyksz8081_ops
#define EXAMPLE_INT ENET_IRQn
#else
#if !defined(FSL_FEATURE_ENET_HAS_AVB) || FSL_FEATURE_ENET_HAS_AVB < 1
#error "This board has no 1G Ethernet port."
#endif
#define EXAMPLE_PHY_ADDRESS BOARD_ENET1_PHY_ADDRESS
#define EXAMPLE_ENET ENET_1G
/* PHY operations. */
#define EXAMPLE_PHY_OPS phyrtl8211f_ops
#define EXAMPLE_INT ENET_1G_IRQn
#endif
/* MDIO operations. */
#define EXAMPLE_MDIO_OPS enet_ops
#define EXAMPLE_CLOCK_FREQ BOARD_GetMDIOClock()
#ifndef PHY_AUTONEGO_TIMEOUT_COUNT
#define PHY_AUTONEGO_TIMEOUT_COUNT (100000)
#endif
#ifndef PHY_STABILITY_DELAY_US
#define PHY_STABILITY_DELAY_US (0U)
#endif
/* Define the driver information structure that is only available within this file. */
AT_NONCACHEABLE_SECTION(static NX_DRIVER_INFORMATION nx_driver_information);
/****** DRIVER SPECIFIC ****** Start of part/vendor specific data area. Include hardware-specific data here! */
/* Define driver specific ethernet hardware address. */
#ifndef NX_DRIVER_ETHERNET_MAC
UCHAR _nx_driver_hardware_address[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x56};
#else
UCHAR _nx_driver_hardware_address[] = NX_DRIVER_ETHERNET_MAC;
#endif
/*! @brief Enet PHY and MDIO interface handler. */
static mdio_handle_t mdioHandle = {.ops = &EXAMPLE_MDIO_OPS};
static phy_handle_t phyHandle = {
.phyAddr = EXAMPLE_PHY_ADDRESS,
.mdioHandle = &mdioHandle,
.ops = &EXAMPLE_PHY_OPS };
/****** DRIVER SPECIFIC ****** End of part/vendor specific data area! */
/* Define the routines for processing each driver entry request. The contents of these routines will change with
each driver. However, the main driver entry function will not change, except for the entry function name. */
static VOID _nx_driver_interface_attach(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_initialize(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_enable(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_disable(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_multicast_join(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_multicast_leave(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_get_status(NX_IP_DRIVER *driver_req_ptr);
#ifdef NX_DRIVER_ENABLE_DEFERRED
static VOID _nx_driver_deferred_processing(NX_IP_DRIVER *driver_req_ptr);
#endif
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
#ifdef NX_DIRVER_INTERNAL_TRANSMIT_QUEUE
static VOID _nx_driver_transmit_packet_enqueue(NX_PACKET *packet_ptr)
static NX_PACKET *_nx_driver_transmit_packet_dequeue(VOID)
#endif
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
static VOID _nx_driver_capability_get(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_capability_set(NX_IP_DRIVER *driver_req_ptr);
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */
/* Define the prototypes for the hardware implementation of this driver. The contents of these routines are
driver-specific. */
static UINT _nx_driver_hardware_initialize(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_enable(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_disable(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr);
static UINT _nx_driver_hardware_multicast_join(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_multicast_leave(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_get_status(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_hardware_packet_transmitted(VOID);
static VOID _nx_driver_hardware_packet_received(VOID);
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
static UINT _nx_driver_hardware_capability_set(NX_IP_DRIVER *driver_req_ptr);
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* nx_driver_imx PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This is the entry point of the NetX Ethernet Driver. This driver */
/* function is responsible for initializing the Ethernet controller, */
/* enabling or disabling the controller as need, preparing */
/* a packet for transmission, and getting status information. */
/* */
/* INPUT */
/* */
/* driver_req_ptr The driver request from the */
/* IP layer. */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_interface_attach Process attach request */
/* _nx_driver_initialize Process initialize request */
/* _nx_driver_enable Process link enable request */
/* _nx_driver_disable Process link disable request */
/* _nx_driver_packet_send Process send packet requests */
/* _nx_driver_multicast_join Process multicast join request*/
/* _nx_driver_multicast_leave Process multicast leave req */
/* _nx_driver_get_status Process get status request */
/* _nx_driver_deferred_processing Drive deferred processing */
/* */
/* CALLED BY */
/* */
/* IP layer */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
/****** DRIVER SPECIFIC ****** Start of part/vendor specific global driver entry function name. */
VOID nx_driver_imx(NX_IP_DRIVER *driver_req_ptr)
/****** DRIVER SPECIFIC ****** End of part/vendor specific global driver entry function name. */
{
/* Default to successful return. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
/* Process according to the driver request type in the IP control
block. */
switch (driver_req_ptr -> nx_ip_driver_command)
{
case NX_LINK_INTERFACE_ATTACH:
/* Process link interface attach requests. */
_nx_driver_interface_attach(driver_req_ptr);
break;
case NX_LINK_INITIALIZE:
{
/* Process link initialize requests. */
_nx_driver_initialize(driver_req_ptr);
break;
}
case NX_LINK_ENABLE:
{
/* Process link enable requests. */
_nx_driver_enable(driver_req_ptr);
break;
}
case NX_LINK_DISABLE:
{
/* Process link disable requests. */
_nx_driver_disable(driver_req_ptr);
break;
}
case NX_LINK_ARP_SEND:
case NX_LINK_ARP_RESPONSE_SEND:
case NX_LINK_PACKET_BROADCAST:
case NX_LINK_RARP_SEND:
case NX_LINK_PACKET_SEND:
{
/* Process packet send requests. */
_nx_driver_packet_send(driver_req_ptr);
break;
}
case NX_LINK_MULTICAST_JOIN:
{
/* Process multicast join requests. */
_nx_driver_multicast_join(driver_req_ptr);
break;
}
case NX_LINK_MULTICAST_LEAVE:
{
/* Process multicast leave requests. */
_nx_driver_multicast_leave(driver_req_ptr);
break;
}
case NX_LINK_GET_STATUS:
{
/* Process get status requests. */
_nx_driver_get_status(driver_req_ptr);
break;
}
#ifdef NX_DRIVER_ENABLE_DEFERRED
case NX_LINK_DEFERRED_PROCESSING:
{
/* Process driver deferred requests. */
/* Process a device driver function on behave of the IP thread. */
_nx_driver_deferred_processing(driver_req_ptr);
break;
}
#endif
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
case NX_INTERFACE_CAPABILITY_GET:
{
/* Process get capability requests. */
_nx_driver_capability_get(driver_req_ptr);
break;
}
case NX_INTERFACE_CAPABILITY_SET:
{
/* Process set capability requests. */
_nx_driver_capability_set(driver_req_ptr);
break;
}
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */
default:
/* Invalid driver request. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_interface_attach PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the interface attach request. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_interface_attach(NX_IP_DRIVER *driver_req_ptr)
{
/* Setup the driver's interface. This example is for a simple one-interface
Ethernet driver. Additional logic is necessary for multiple port devices. */
nx_driver_information.nx_driver_information_interface = driver_req_ptr -> nx_ip_driver_interface;
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
driver_req_ptr -> nx_ip_driver_interface -> nx_interface_capability_flag = NX_DRIVER_CAPABILITY;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */
/* Return successful status. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_initialize PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the initialize request. The processing */
/* in this function is generic. All ethernet controller logic is to */
/* be placed in _nx_driver_hardware_initialize. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_initialize Process initialize request */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_initialize(NX_IP_DRIVER *driver_req_ptr)
{
NX_IP *ip_ptr;
NX_INTERFACE *interface_ptr;
UINT status;
/* Setup the IP pointer from the driver request. */
ip_ptr = driver_req_ptr -> nx_ip_driver_ptr;
/* Setup interface pointer. */
interface_ptr = driver_req_ptr -> nx_ip_driver_interface;
/* Initialize the driver's information structure. */
/* Default IP pointer to NULL. */
nx_driver_information.nx_driver_information_ip_ptr = NX_NULL;
/* Setup the driver state to not initialized. */
nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_NOT_INITIALIZED;
/* Setup the default packet pool for the driver's received packets. */
nx_driver_information.nx_driver_information_packet_pool_ptr = ip_ptr -> nx_ip_default_packet_pool;
/* Clear the deferred events for the driver. */
nx_driver_information.nx_driver_information_deferred_events = 0;
#ifdef NX_DIRVER_INTERNAL_TRANSMIT_QUEUE
/* Clear the transmit queue count and head pointer. */
nx_driver_information.nx_driver_transmit_packets_queued = 0;
nx_driver_information.nx_driver_transmit_queue_head = NX_NULL;
nx_driver_information.nx_driver_transmit_queue_tail = NX_NULL;
#endif
/* Call the hardware-specific ethernet controller initialization. */
status = _nx_driver_hardware_initialize(driver_req_ptr);
/* Determine if the request was successful. */
if (status == NX_SUCCESS)
{
/* Successful hardware initialization. */
/* Setup driver information to point to IP pointer. */
nx_driver_information.nx_driver_information_ip_ptr = driver_req_ptr -> nx_ip_driver_ptr;
/* Setup the link maximum transfer unit. */
interface_ptr -> nx_interface_ip_mtu_size = NX_DRIVER_ETHERNET_MTU - NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Setup the physical address of this IP instance. Increment the
physical address lsw to simulate multiple nodes hanging on the
ethernet. */
interface_ptr -> nx_interface_physical_address_msw =
(ULONG)((_nx_driver_hardware_address[0] << 8) | (_nx_driver_hardware_address[1]));
interface_ptr -> nx_interface_physical_address_lsw =
(ULONG)((_nx_driver_hardware_address[2] << 24) | (_nx_driver_hardware_address[3] << 16) |
(_nx_driver_hardware_address[4] << 8) | (_nx_driver_hardware_address[5]));
/* Indicate to the IP software that IP to physical mapping
is required. */
interface_ptr -> nx_interface_address_mapping_needed = NX_TRUE;
/* Move the driver's state to initialized. */
nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;
/* Indicate successful initialize. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
else
{
/* Initialization failed. Indicate that the request failed. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_enable PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the initialize request. The processing */
/* in this function is generic. All ethernet controller logic is to */
/* be placed in _nx_driver_hardware_enable. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_enable Process enable request */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_enable(NX_IP_DRIVER *driver_req_ptr)
{
UINT status;
/* See if we can honor the NX_LINK_ENABLE request. */
if (nx_driver_information.nx_driver_information_state < NX_DRIVER_STATE_INITIALIZED)
{
/* Mark the request as not successful. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
return;
}
/* Check if it is enabled by someone already */
if (nx_driver_information.nx_driver_information_state >= NX_DRIVER_STATE_LINK_ENABLED)
{
/* Yes, the request has already been made. */
driver_req_ptr -> nx_ip_driver_status = NX_ALREADY_ENABLED;
return;
}
/* Call hardware specific enable. */
status = _nx_driver_hardware_enable(driver_req_ptr);
/* Was the hardware enable successful? */
if (status == NX_SUCCESS)
{
/* Update the driver state to link enabled. */
nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_LINK_ENABLED;
/* Mark request as successful. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
/* Mark the IP instance as link up. */
driver_req_ptr -> nx_ip_driver_interface -> nx_interface_link_up = NX_TRUE;
}
else
{
/* Enable failed. Indicate that the request failed. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_disable PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the disable request. The processing */
/* in this function is generic. All ethernet controller logic is to */
/* be placed in _nx_driver_hardware_disable. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_disable Process disable request */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_disable(NX_IP_DRIVER *driver_req_ptr)
{
NX_IP *ip_ptr;
UINT status;
/* Setup the IP pointer from the driver request. */
ip_ptr = driver_req_ptr -> nx_ip_driver_ptr;
/* Check if the link is enabled. */
if (nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
{
/* The link is not enabled, so just return an error. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
return;
}
/* Call hardware specific disable. */
status = _nx_driver_hardware_disable(driver_req_ptr);
/* Was the hardware disable successful? */
if (status == NX_SUCCESS)
{
/* Mark the IP instance as link down. */
ip_ptr -> nx_ip_driver_link_up = NX_FALSE;
/* Update the driver state back to initialized. */
nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;
/* Mark request as successful. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
else
{
/* Disable failed, return an error. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_packet_send PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the packet send request. The processing */
/* in this function is generic. All ethernet controller packet send */
/* logic is to be placed in _nx_driver_hardware_packet_send. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_packet_send Process packet send request */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr)
{
NX_PACKET *packet_ptr;
ULONG *ethernet_frame_ptr;
UINT status;
/* Check to make sure the link is up. */
if (nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
{
/* Inidate an unsuccessful packet send. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
/* Link is not up, simply free the packet. */
nx_packet_transmit_release(driver_req_ptr -> nx_ip_driver_packet);
return;
}
/* Process driver send packet. */
/* Place the ethernet frame at the front of the packet. */
packet_ptr = driver_req_ptr -> nx_ip_driver_packet;
/* Adjust the prepend pointer. */
packet_ptr -> nx_packet_prepend_ptr =
packet_ptr -> nx_packet_prepend_ptr - NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Adjust the packet length. */
packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Setup the ethernet frame pointer to build the ethernet frame. Backup another 2
* bytes to get 32-bit word alignment. */
ethernet_frame_ptr = (ULONG *) (packet_ptr -> nx_packet_prepend_ptr - 2);
/* Set up the hardware addresses in the Ethernet header. */
*ethernet_frame_ptr = driver_req_ptr -> nx_ip_driver_physical_address_msw;
*(ethernet_frame_ptr + 1) = driver_req_ptr -> nx_ip_driver_physical_address_lsw;
*(ethernet_frame_ptr + 2) = (driver_req_ptr -> nx_ip_driver_interface -> nx_interface_physical_address_msw << 16) |
(driver_req_ptr -> nx_ip_driver_interface -> nx_interface_physical_address_lsw >> 16);
*(ethernet_frame_ptr + 3) = (driver_req_ptr -> nx_ip_driver_interface -> nx_interface_physical_address_lsw << 16);
/* Set up the frame type field in the Ethernet harder. */
if ((driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND)||
(driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND))
{
*(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_ARP;
}
else if(driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND)
{
*(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_RARP;
}
#ifdef FEATURE_NX_IPV6
else if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
{
*(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_IPV6;
}
#endif
else
{
*(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_IP;
}
/* Endian swapping if NX_LITTLE_ENDIAN is defined. */
NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 1));
NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 2));
NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 3));
/* Determine if the packet exceeds the driver's MTU. */
if (packet_ptr -> nx_packet_length > NX_DRIVER_ETHERNET_MTU)
{
/* This packet exceeds the size of the driver's MTU. Simply throw it away! */
/* Remove the Ethernet header. */
NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);
/* Indicate an unsuccessful packet send. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
/* Link is not up, simply free the packet. */
nx_packet_transmit_release(packet_ptr);
return;
}
/* Transmit the packet through the Ethernet controller low level access routine. */
status = _nx_driver_hardware_packet_send(packet_ptr);
/* Determine if there was an error. */
if (status != NX_SUCCESS)
{
/* Driver's hardware send packet routine failed to send the packet. */
/* Remove the Ethernet header. */
NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);
/* Indicate an unsuccessful packet send. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
/* Link is not up, simply free the packet. */
nx_packet_transmit_release(packet_ptr);
}
else
{
/* Set the status of the request. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_multicast_join PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the multicast join request. The processing */
/* in this function is generic. All ethernet controller multicast join */
/* logic is to be placed in _nx_driver_hardware_multicast_join. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_multicast_join Process multicast join request*/
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_multicast_join(NX_IP_DRIVER *driver_req_ptr)
{
UINT status;
if (nx_driver_information.nx_driver_information_state >= NX_DRIVER_STATE_INITIALIZED)
{
/* Call hardware specific multicast join function. */
status = _nx_driver_hardware_multicast_join(driver_req_ptr);
}
else
{
status = NX_NOT_ENABLED;
}
/* Determine if there was an error. */
if (status != NX_SUCCESS)
{
/* Indicate an unsuccessful request. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
else
{
/* Indicate the request was successful. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_multicast_leave PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the multicast leave request. The */
/* processing in this function is generic. All ethernet controller */
/* multicast leave logic is to be placed in */
/* _nx_driver_hardware_multicast_leave. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_multicast_leave Process multicast leave req */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_multicast_leave(NX_IP_DRIVER *driver_req_ptr)
{
UINT status;
if (nx_driver_information.nx_driver_information_state >= NX_DRIVER_STATE_INITIALIZED)
{
/* Call hardware specific multicast leave function. */
status = _nx_driver_hardware_multicast_leave(driver_req_ptr);
}
else
{
status = NX_NOT_ENABLED;
}
/* Determine if there was an error. */
if (status != NX_SUCCESS)
{
/* Indicate an unsuccessful request. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
else
{
/* Indicate the request was successful. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_get_status PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the get status request. The processing */
/* in this function is generic. All ethernet controller get status */
/* logic is to be placed in _nx_driver_hardware_get_status. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_hardware_get_status Process get status request */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_get_status(NX_IP_DRIVER *driver_req_ptr)
{
UINT status;
/* Call hardware specific get status function. */
status = _nx_driver_hardware_get_status(driver_req_ptr);
/* Determine if there was an error. */
if (status != NX_SUCCESS)
{
/* Indicate an unsuccessful request. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
else
{
/* Indicate the request was successful. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
}
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_capability_get PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the get capability request. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 01-01-2014 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_capability_get(NX_IP_DRIVER *driver_req_ptr)
{
/* Return the capability of the Ethernet controller. */
*(driver_req_ptr -> nx_ip_driver_return_ptr) = NX_DRIVER_CAPABILITY;
/* Return the success status. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_capability_set PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the set capability request. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 01-01-2014 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_capability_set(NX_IP_DRIVER *driver_req_ptr)
{
UINT status;
/* Call hardware specific get status function. */
status = _nx_driver_hardware_capability_set(driver_req_ptr);
/* Determine if there was an error. */
if (status != NX_SUCCESS)
{
/* Indicate an unsuccessful request. */
driver_req_ptr -> nx_ip_driver_status = NX_DRIVER_ERROR;
}
else
{
/* Indicate the request was successful. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
}
}
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */
#ifdef NX_DRIVER_ENABLE_DEFERRED
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_deferred_processing PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* XC, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing the deferred ISR action within the context */
/* of the IP thread. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver command from the IP */
/* thread */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_packet_transmitted Clean up after transmission */
/* _nx_driver_packet_received Process a received packet */
/* */
/* CALLED BY */
/* */
/* Driver entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_deferred_processing(NX_IP_DRIVER *driver_req_ptr)
{
TX_INTERRUPT_SAVE_AREA
ULONG deferred_events;
/* Disable interrupts. */
TX_DISABLE
/* Pickup deferred events. */
deferred_events = nx_driver_information.nx_driver_information_deferred_events;
nx_driver_information.nx_driver_information_deferred_events = 0;
/* Restore interrupts. */
TX_RESTORE
/* Check for a transmit complete event. */
if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED)
{
/* Process transmitted packet(s). */
_nx_driver_hardware_packet_transmitted();
}
/* Check for received packet. */
if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED)
{
/* Process received packet(s). */
_nx_driver_hardware_packet_received();
}
/* Mark request as successful. */
driver_req_ptr->nx_ip_driver_status = NX_SUCCESS;
}
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_transfer_to_netx PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing incoming packets. This routine would */
/* be called from the driver-specific receive packet processing */
/* function _nx_driver_hardware_packet_received. */
/* */
/* INPUT */
/* */
/* ip_ptr Pointer to IP protocol block */
/* packet_ptr Packet pointer */
/* */
/* OUTPUT */
/* */
/* Error indication */
/* */
/* CALLS */
/* */
/* _nx_ip_packet_receive NetX IP packet receive */
/* _nx_ip_packet_deferred_receive NetX IP packet receive */
/* _nx_arp_packet_deferred_receive NetX ARP packet receive */
/* _nx_rarp_packet_deferred_receive NetX RARP packet receive */
/* _nx_packet_release Release packet */
/* */
/* CALLED BY */
/* */
/* _nx_driver_hardware_packet_received Driver packet receive function*/
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
{
USHORT packet_type;
packet_ptr -> nx_packet_ip_interface = nx_driver_information.nx_driver_information_interface;
/* Pickup the packet header to determine where the packet needs to be
sent. */
packet_type = (USHORT)(((UINT) (*(packet_ptr -> nx_packet_prepend_ptr+12))) << 8) |
((UINT) (*(packet_ptr -> nx_packet_prepend_ptr+13)));
/* Route the incoming packet according to its ethernet type. */
if (packet_type == NX_DRIVER_ETHERNET_IP || packet_type == NX_DRIVER_ETHERNET_IPV6)
{
/* Note: The length reported by some Ethernet hardware includes
bytes after the packet as well as the Ethernet header. In some
cases, the actual packet length after the Ethernet header should
be derived from the length in the IP header (lower 16 bits of
the first 32-bit word). */
/* Clean off the Ethernet header. */
packet_ptr -> nx_packet_prepend_ptr =
packet_ptr -> nx_packet_prepend_ptr + NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Adjust the packet length. */
packet_ptr -> nx_packet_length =
packet_ptr -> nx_packet_length - NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Route to the ip receive function. */
#ifdef NX_DRIVER_ENABLE_DEFERRED
_nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
#else
_nx_ip_packet_receive(ip_ptr, packet_ptr);
#endif
}
else if (packet_type == NX_DRIVER_ETHERNET_ARP)
{
/* Clean off the Ethernet header. */
packet_ptr -> nx_packet_prepend_ptr =
packet_ptr -> nx_packet_prepend_ptr + NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Adjust the packet length. */
packet_ptr -> nx_packet_length =
packet_ptr -> nx_packet_length - NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Route to the ARP receive function. */
_nx_arp_packet_deferred_receive(ip_ptr, packet_ptr);
}
else if (packet_type == NX_DRIVER_ETHERNET_RARP)
{
/* Clean off the Ethernet header. */
packet_ptr -> nx_packet_prepend_ptr =
packet_ptr -> nx_packet_prepend_ptr + NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Adjust the packet length. */
packet_ptr -> nx_packet_length =
packet_ptr -> nx_packet_length - NX_DRIVER_ETHERNET_FRAME_SIZE;
/* Route to the RARP receive function. */
_nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr);
}
else
{
/* Invalid ethernet header... release the packet. */
nx_packet_release(packet_ptr);
}
}
#ifdef NX_DIRVER_INTERNAL_TRANSMIT_QUEUE
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_transmit_packet_enqueue PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function queues a transmit packet when the hardware transmit */
/* queue does not have the resources (buffer descriptors, etc.) to */
/* send the packet. The queue is maintained as a singularly linked- */
/* list with head and tail pointers. The maximum number of packets on */
/* the transmit queue is regulated by the constant */
/* NX_DRIVER_MAX_TRANSMIT_QUEUE_DEPTH. When this number is exceeded, */
/* the oldest packet is discarded after the new packet is queued. */
/* */
/* Note: that it is assumed further driver interrupts are locked out */
/* during the call to this driver utility. */
/* */
/* INPUT */
/* */
/* packet_ptr Packet pointer */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_packet_transmit_release Release packet */
/* */
/* CALLED BY */
/* */
/* _nx_driver_hardware_packet_send Driver packet send function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_transmit_packet_enqueue(NX_PACKET *packet_ptr)
{
/* Determine if there is anything on the queue. */
if (nx_driver_information.nx_driver_transmit_queue_tail)
{
/* Yes, something is on the transmit queue. Simply add the new packet to the
tail. */
nx_driver_information.nx_driver_transmit_queue_tail -> nx_packet_queue_next = packet_ptr;
/* Update the tail pointer. */
nx_driver_information.nx_driver_transmit_queue_tail = packet_ptr;
}
else
{
/* First packet on the transmit queue. */
/* Setup head pointers. */
nx_driver_information.nx_driver_transmit_queue_head = packet_ptr;
nx_driver_information.nx_driver_transmit_queue_tail = packet_ptr;
/* Set the packet's next pointer to NULL. */
packet_ptr -> nx_packet_queue_next = NX_NULL;
}
/* Increment the total packets queued. */
nx_driver_information.nx_driver_transmit_packets_queued++;
/* Determine if the total packet queued exceeds the driver's maximum transmit
queue depth. */
if (nx_driver_information.nx_driver_transmit_packets_queued > NX_DRIVER_MAX_TRANSMIT_QUEUE_DEPTH)
{
/* Yes, remove the head packet (oldest) packet in the transmit queue and release it. */
packet_ptr = nx_driver_information.nx_driver_transmit_queue_head;
/* Adjust the head pointer to the next packet. */
nx_driver_information.nx_driver_transmit_queue_head = packet_ptr -> nx_packet_queue_next;
/* Decrement the transmit packet queued count. */
nx_driver_information.nx_driver_transmit_packets_queued--;
/* Remove the ethernet header. */
NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);
/* Release the packet. */
nx_packet_transmit_release(packet_ptr);
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_transmit_packet_dequeue PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function removes the oldest transmit packet when the hardware */
/* transmit queue has new resources (usually after a transmit complete */
/* interrupt) to send the packet. If there are no packets in the */
/* transmit queue, a NULL is returned. */
/* */
/* Note: that it is assumed further driver interrupts are locked out */
/* during the call to this driver utility. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* packet_ptr Packet pointer */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_driver_hardware_packet_send Driver packet send function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static NX_PACKET *_nx_driver_transmit_packet_dequeue(VOID)
{
NX_PACKET *packet_ptr;
/* Pickup the head pointer of the tranmit packet queue. */
packet_ptr = nx_driver_information.nx_driver_transmit_queue_head;
/* Determine if there is anything on the queue. */
if (packet_ptr)
{
/* Yes, something is on the transmit queue. Simply the packet from the head of the queue. */
/* Update the head pointer. */
nx_driver_information.nx_driver_transmit_queue_head = packet_ptr -> nx_packet_queue_next;
/* Clear the next pointer in the packet. */
packet_ptr -> nx_packet_queue_next = NX_NULL;
/* Decrement the transmit packet queued count. */
nx_driver_information.nx_driver_transmit_packets_queued--;
}
/* Return the packet pointer - NULL if there are no packets queued. */
return(packet_ptr);
}
#endif
/****** DRIVER SPECIFIC ****** Start of part/vendor specific internal driver functions. */
typedef struct
{
enet_mii_mode_t interface; /* Transceiver mode */
uint8_t neg; /* FEC autoneg */
phy_speed_t speed; /* Ethernet Speed */
phy_duplex_t duplex; /* Ethernet Duplex */
uint8_t mac[6]; /* Ethernet Address */
} ENET_CONFIG_IMX;
VOID nx_driver_link_mode_changed(VOID);
VOID nx_driver_imx_ethernet_isr(VOID);
void enet_init_imx(ENET_CONFIG_IMX *config)
{
volatile uint32_t rcr = 0;
volatile uint32_t ecr = 0;
volatile uint32_t tcr = 0;
/* Clear the Individual and Group Address Hash registers */
EXAMPLE_ENET->IALR/*(ch)*/ = 0;
EXAMPLE_ENET->IAUR/*(ch)*/ = 0;
EXAMPLE_ENET->GALR/*(ch)*/ = 0;
EXAMPLE_ENET->GAUR/*(ch)*/ = 0;
/* Set the Physical Address for the selected FEC */
/*enet_set_address(config->ch, config->mac);*/
ENET_SetMacAddr(EXAMPLE_ENET,config->mac);
/* Mask all FEC interrupts */
EXAMPLE_ENET->EIMR/*(ch)*/ = 0;/*FSL:ENET_EIMR_MASK_ALL_MASK;*/
/* Clear all FEC interrupt events */
EXAMPLE_ENET->EIR/*(ch)*/ = 0xFFFFFFFF;/*FSL:ENET_EIR_CLEAR_ALL_MASK;*/
/* Initialize the Receive Control Register */
rcr = ENET_RCR_MAX_FL(14+1500+4) /*ethernet frame head + max data+crc*/
| ENET_RCR_MII_MODE_MASK /*always*/
| ENET_RCR_CRCFWD_MASK; /*no CRC pad required*/
#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(EXAMPLE_ENET) == 1)
{
if ( config->interface == kENET_RgmiiMode )
{
rcr |= ENET_RCR_RGMII_EN_MASK;
}
else
{
rcr &= ~ENET_RCR_RGMII_EN_MASK;
}
if( config->speed == kPHY_Speed1000M )
{
ecr |= ENET_ECR_SPEED_MASK;
}
else
{
ecr &= ~ENET_ECR_SPEED_MASK;
}
/* use Round-robin scheme for legacy buffer descriptor mode */
EXAMPLE_ENET->QOS |= ENET_QOS_TX_SCHEME(1);
}
#endif
if ( config->interface == kENET_RmiiMode )
{
rcr |= ENET_RCR_RMII_MODE_MASK;
/*only set speed in RMII mode*/
if( config->speed == kPHY_Speed10M )
{
rcr |= ENET_RCR_RMII_10T_MASK;
}
}/*no need to configure MAC MII interface*/
/* Set the duplex */
switch (config->duplex)
{
case kENET_MiiHalfDuplex:
rcr |= ENET_RCR_DRT_MASK;
tcr &= (uint32_t)~ENET_TCR_FDEN_MASK;
break;
case kENET_MiiFullDuplex:
default:
rcr &= ~ENET_RCR_DRT_MASK;
tcr |= ENET_TCR_FDEN_MASK;
break;
}
#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
ecr |= ENET_ECR_EN1588_MASK;
#endif
#ifdef IMX_CHECKSUM_OFFLOAD
EXAMPLE_ENET->TACC = ENET_TACC_SHIFT16_MASK |
ENET_TACC_IPCHK_MASK |
ENET_TACC_PROCHK_MASK;
EXAMPLE_ENET->TFWR = ENET_TFWR_STRFWD_MASK;
EXAMPLE_ENET->RACC = ENET_RACC_SHIFT16_MASK |
ENET_RACC_LINEDIS_MASK |
ENET_RACC_PRODIS_MASK |
ENET_RACC_IPDIS_MASK;
#else
EXAMPLE_ENET->TACC = ENET_TACC_SHIFT16_MASK;
EXAMPLE_ENET->RACC = ENET_RACC_SHIFT16_MASK |
ENET_RACC_LINEDIS_MASK;
#endif
EXAMPLE_ENET->RCR = rcr;
EXAMPLE_ENET->ECR = ecr;
EXAMPLE_ENET->TCR = tcr;
}
void enet_init()
{
phy_config_t phyConfig = {0};
bool link = false;
bool autonego = false;
uint32_t count = 0;
status_t status;
phy_speed_t speed;
phy_duplex_t duplex;
ENET_CONFIG_IMX econf;
#if defined(BOARD_NETWORK_USE_100M_ENET_PORT) && (BOARD_NETWORK_USE_100M_ENET_PORT == 1)
econf.interface = kENET_RmiiMode;
#else
econf.interface = kENET_RgmiiMode;
#endif
econf.neg = 0; /*autoneg on */
econf.mac[0] = _nx_driver_hardware_address[0];
econf.mac[1] = _nx_driver_hardware_address[1];
econf.mac[2] = _nx_driver_hardware_address[2];
econf.mac[3] = _nx_driver_hardware_address[3];
econf.mac[4] = _nx_driver_hardware_address[4];
econf.mac[5] = _nx_driver_hardware_address[5];
phyConfig.phyAddr = EXAMPLE_PHY_ADDRESS;
phyConfig.autoNeg = true;
mdioHandle.resource.base = EXAMPLE_ENET;
mdioHandle.resource.csrClock_Hz = EXAMPLE_CLOCK_FREQ;
/* Initialize PHY and wait auto-negotiation over. */
do
{
status = PHY_Init(&phyHandle, &phyConfig);
if (status == kStatus_Success)
{
/* Wait for auto-negotiation success and link up */
count = PHY_AUTONEGO_TIMEOUT_COUNT;
do
{
PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
PHY_GetLinkStatus(&phyHandle, &link);
if (autonego && link)
{
break;
}
} while (--count);
if (!autonego)
{
PRINTF("PHY Auto-negotiation failed. Please check the cable connection and link partner setting.\r\n");
}
}
} while (!(link && autonego));
#if PHY_STABILITY_DELAY_US
/* Wait a moment for PHY status to be stable. */
SDK_DelayAtLeastUs(PHY_STABILITY_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
#endif
PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex);
econf.speed = speed;
econf.duplex = duplex;
enet_init_imx(&econf);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_initialize PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific initialization. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver request pointer */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* ETH_BSP_Config Configure Ethernet */
/* ETH_MACAddressConfig Setup MAC address */
/* ETH_DMARxDescReceiveITConfig Enable receive descriptors */
/* nx_packet_allocate Allocate receive packet(s) */
/* */
/* CALLED BY */
/* */
/* _nx_driver_initialize Driver initialize processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_initialize(NX_IP_DRIVER *driver_req_ptr)
{
NX_PACKET *packet_ptr;
UINT i;
/* Default to successful return. */
driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS;
/* Setup indices. */
nx_driver_information.nx_driver_information_receive_current_index = 0;
nx_driver_information.nx_driver_information_transmit_current_index = 0;
nx_driver_information.nx_driver_information_transmit_release_index = 0;
/* Clear the number of buffers in use counter. */
nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use = 0;
/* Make sure there are receive packets... otherwise, return an error. */
if (nx_driver_information.nx_driver_information_packet_pool_ptr == NULL)
{
/* There must be receive packets. If not, return an error! */
return(NX_DRIVER_ERROR);
}
enet_init();
/* Initialize TX Descriptors list: Ring Mode. */
/* Make sure Number of Buffer Descriptors is power of 2 */
#if (NX_DRIVER_TX_DESCRIPTORS & (NX_DRIVER_TX_DESCRIPTORS - 1)) != 0
#error "Number of Buffer Descriptors must be power of 2"
#endif
nx_driver_information.nx_driver_information_dma_tx_descriptors = (enet_tx_bd_struct_t*)(((UINT)nx_driver_information.nx_driver_information_dma_tx_descriptors_area + 15) & (~15));
/* Fill each DMATxDesc descriptor with the right values. */
for(i = 0; i < NX_DRIVER_TX_DESCRIPTORS; i++)
{
/* Initialize tx descriptors. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[i].control = ENET_BUFFDESCRIPTOR_TX_TRANMITCRC_MASK;
nx_driver_information.nx_driver_information_dma_tx_descriptors[i].length = 0;
#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
#ifdef IMX_CHECKSUM_OFFLOAD
/* Enable tx interrupt & checksum offload. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[i].controlExtend1 = ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK | 0x0800 | 0x1000;
#else
/* Enable tx interrupt. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[i].controlExtend1 = ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK;
#endif
#endif
nx_driver_information.nx_driver_information_transmit_packets[i] = NX_NULL;
}
/* Put the Wrap indicaiton on the last descriptor. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[NX_DRIVER_TX_DESCRIPTORS - 1].control |= ENET_BUFFDESCRIPTOR_TX_WRAP_MASK;
/* Set Transmit Descriptor List Address Register */
EXAMPLE_ENET->TDSR = (ULONG) nx_driver_information.nx_driver_information_dma_tx_descriptors;
/* Initialize RX Descriptors list: Ring Mode */
/* Make sure Number of Buffer Descriptors is power of 2 */
#if (NX_DRIVER_RX_DESCRIPTORS & (NX_DRIVER_RX_DESCRIPTORS - 1)) != 0
#error "Number of Buffer Descriptors must be power of 2"
#endif
nx_driver_information.nx_driver_information_dma_rx_descriptors = (enet_rx_bd_struct_t*)(((UINT)nx_driver_information.nx_driver_information_dma_rx_descriptors_area + 15) & (~15));
/* Fill each DMARxDesc descriptor with the right values */
for(i = 0; i < NX_DRIVER_RX_DESCRIPTORS; i++)
{
nx_driver_information.nx_driver_information_dma_rx_descriptors[i].length = 0;
/* Allocate a packet for the receive buffers. */
if (nx_packet_allocate(nx_driver_information.nx_driver_information_packet_pool_ptr, &packet_ptr,
NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS)
{
nx_driver_information.nx_driver_information_dma_rx_descriptors[i].control = ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
nx_driver_information.nx_driver_information_dma_rx_descriptors[i].controlExtend2 = 0x0000;
nx_driver_information.nx_driver_information_dma_rx_descriptors[i].controlExtend1 = ENET_BUFFDESCRIPTOR_RX_BROADCAST_MASK;
#endif
nx_driver_information.nx_driver_information_dma_rx_descriptors[i].buffer = (uint8_t *)(uint32_t)packet_ptr->nx_packet_prepend_ptr;
nx_driver_information.nx_driver_information_receive_packets[i] = packet_ptr;
}
else
{
/* Cannot allocate packets from the packet pool. */
return(NX_DRIVER_ERROR);
}
}
/* Put the Wrap indicaiton on the last descriptor. */
nx_driver_information.nx_driver_information_dma_rx_descriptors[NX_DRIVER_RX_DESCRIPTORS - 1].control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK | ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
/* Save the size of one rx buffer. */
nx_driver_information.nx_driver_information_rx_buffer_size = packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start;
/* Configure the Receive Buffer Size Register. */
EXAMPLE_ENET->MRBR = nx_driver_information.nx_driver_information_rx_buffer_size;
/* Set Receive Descriptor List Address Register. */
EXAMPLE_ENET->RDSR = (ULONG) nx_driver_information.nx_driver_information_dma_rx_descriptors;
for (i = 0; i < 64; i++)
{
nx_driver_information.nx_driver_information_multicast_count[i] = 0;
}
/* Return success! */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_enable PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific link enable requests. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver request pointer */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* */
/* CALLED BY */
/* */
/* _nx_driver_enable Driver link enable processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_enable(NX_IP_DRIVER *driver_req_ptr)
{
/* Enable Ethernet interrupt. */
EXAMPLE_ENET->EIMR |= ENET_EIMR_RXF_MASK | ENET_EIMR_TXF_MASK;
/* Start Ethernet. */
/*The buffer descriptor bytes are swapped to support little-endian devices.*/
/* The DBSWP field must be written to 1 after reset*/
EXAMPLE_ENET->ECR |= ENET_ECR_ETHEREN_MASK | ENET_ECR_DBSWP_MASK;
EnableIRQ(EXAMPLE_INT);
/*active rx descriptor*/
EXAMPLE_ENET->RDAR = ENET_RDAR_RDAR_MASK;
/* Return success! */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_disable PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific link disable requests. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver request pointer */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* */
/* CALLED BY */
/* */
/* _nx_driver_disable Driver link disable processing*/
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_disable(NX_IP_DRIVER *driver_req_ptr)
{
DisableIRQ(EXAMPLE_INT);
/* Stop the Ethernet. */
EXAMPLE_ENET->ECR &= ~ENET_ECR_ETHEREN_MASK;
/* Return success! */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_packet_send PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific packet send requests. */
/* */
/* INPUT */
/* */
/* packet_ptr Pointer to packet to send */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* [_nx_driver_transmit_packet_enqueue] Optional internal transmit */
/* packet queue routine */
/* */
/* CALLED BY */
/* */
/* _nx_driver_packet_send Driver packet send processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
ULONG curIdx;
NX_PACKET *pktIdx;
ULONG bd_count = 0;
UCHAR remainder = 0;
UCHAR* src_addr;
/* Pick up the first BD. */
curIdx = nx_driver_information.nx_driver_information_transmit_current_index;
/* Check if it is a free descriptor. */
if ((nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) || nx_driver_information.nx_driver_information_transmit_packets[curIdx])
{
/* Buffer is still owned by device. */
return(NX_DRIVER_ERROR);
}
/* Set the buffer size. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].length = (packet_ptr -> nx_packet_append_ptr - packet_ptr->nx_packet_prepend_ptr + 2);
remainder = (UCHAR )((ULONG)(packet_ptr->nx_packet_prepend_ptr - 2)& 0x07);
if(remainder)
{
src_addr = packet_ptr->nx_packet_prepend_ptr;
/*make sure transmit BD buffer 8byte aligment*/
packet_ptr->nx_packet_prepend_ptr -= remainder;
memmove(packet_ptr->nx_packet_prepend_ptr,src_addr,nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].length);
}
/* Find the Buffer, set the Buffer pointer. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].buffer = (uint8_t *)(ULONG)(packet_ptr->nx_packet_prepend_ptr - 2);
/* Clear the first Descriptor's LS bit. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].control &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
/* Find next packet. */
for (pktIdx = packet_ptr -> nx_packet_next;
pktIdx != NX_NULL;
pktIdx = pktIdx -> nx_packet_next)
{
/* Move to next descriptor. */
curIdx = (curIdx + 1) & (NX_DRIVER_TX_DESCRIPTORS - 1);
/* Check if it is a free descriptor. */
if ((nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) || nx_driver_information.nx_driver_information_transmit_packets[curIdx])
{
/* No more descriptor available, return driver error status. */
return(NX_DRIVER_ERROR);
}
/* Find the Buffer, set the Buffer pointer. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].buffer = (uint8_t *)(ULONG)(pktIdx->nx_packet_prepend_ptr);
/* Set the buffer size. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].length = (pktIdx -> nx_packet_append_ptr - pktIdx->nx_packet_prepend_ptr);
/* Clear the descriptor's LS bit. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].control &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
/* Increment the BD count. */
bd_count++;
}
/* Set the last Descriptor's LS & IC & OWN bit. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].control |= (ENET_BUFFDESCRIPTOR_TX_LAST_MASK | ENET_BUFFDESCRIPTOR_TX_READY_MASK);
/* Save the pkt pointer to release. */
nx_driver_information.nx_driver_information_transmit_packets[curIdx] = packet_ptr;
/* Set the current index to the next descriptor. */
nx_driver_information.nx_driver_information_transmit_current_index = (curIdx + 1) & (NX_DRIVER_TX_DESCRIPTORS - 1);
/* Increment the transmit buffers in use count. */
nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use += bd_count + 1;
/* Set OWN bit to indicate BDs are ready. */
for (; bd_count > 0; bd_count--)
{
/* Set OWN bit in reverse order, move to prevous BD. */
curIdx = (curIdx - 1) & (NX_DRIVER_TX_DESCRIPTORS - 1);
/* Set this BD's OWN bit. */
nx_driver_information.nx_driver_information_dma_tx_descriptors[curIdx].control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
}
/* If the DMA transmission is suspended, resume transmission. */
if (!EXAMPLE_ENET->TDAR)
{
/* Resume DMA transmission. */
EXAMPLE_ENET->TDAR = ENET_TDAR_TDAR_MASK;
}
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* nx_crc32() PORTABLE C */
/* 1.0 */
/* AUTHOR */
/* */
/* SK - Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* Calculate 32bit CRC using reversed Poly for Ethernet. */
/* */
/* INPUT */
/* */
/* UCHAR dbuf[] - pointer to the data buffer. */
/* INT length - Length of the data */
/* */
/* OUTPUT */
/* */
/* CRC value */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_driver_hardware_multicast_join */
/* _nx_driver_hardware_multicast_leave */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-09-2007 SK Initial Version 1.0 */
/* */
/**************************************************************************/
static ULONG nx_crc32(UCHAR dbuf[], INT length)
{
INT i;
INT bit;
ULONG crc = 0xFFFFFFFFUL;
ULONG poly = 0xEDB88320UL;
ULONG p;
ULONG data;
for (i = 0; i < length; i++)
{
data = ((ULONG)dbuf[i]);
for (bit = 0; bit < 8; bit++)
{
p = (crc ^ ((ULONG)data)) & 1UL;
crc >>= 1;
if (p != 0)
crc ^= poly;
data >>= 1;
}
}
return ~crc;
} /* nx_crc32 */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_multicast_join PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific multicast join requests. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver request pointer */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_driver_multicast_join Driver multicast join */
/* processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_multicast_join(NX_IP_DRIVER *driver_req_ptr)
{
UCHAR adr[NX_DRIVER_PHYSICAL_ADDRESS_SIZE] ;
INT h_val;
ULONG crc_val;
/* Set up the array to pass to the hash_value function. */
adr[0] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_msw >> 8);
adr[1] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_msw);
adr[2] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw >> 24);
adr[3] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw >> 16);
adr[4] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw >> 8);
adr[5] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw);
/* Get the CRC done. */
crc_val = nx_crc32(adr, NX_DRIVER_PHYSICAL_ADDRESS_SIZE);
/* Use only 6 MSbs to obtain value in range 0..63. */
crc_val >>= (32 - 6);
h_val = 63 - (int) crc_val ; /* pointer to 48 bit address */
if(nx_driver_information.nx_driver_information_multicast_count[h_val] == 255)
{
return NX_NO_MORE_ENTRIES;
}
nx_driver_information.nx_driver_information_multicast_count[h_val]++;
if (h_val < 32)
EXAMPLE_ENET->GALR |= 1 << h_val;
else
EXAMPLE_ENET->GAUR |= 1 << (h_val - 32);
/* Return success. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_multicast_leave PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific multicast leave requests. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver request pointer */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_driver_multicast_leave Driver multicast leave */
/* processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_multicast_leave(NX_IP_DRIVER *driver_req_ptr)
{
UCHAR adr[NX_DRIVER_PHYSICAL_ADDRESS_SIZE] ;
INT h_val;
ULONG crc_val;
/* Set up the array to pass to the hash_value function. */
adr[0] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_msw >> 8);
adr[1] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_msw);
adr[2] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw >> 24);
adr[3] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw >> 16);
adr[4] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw >> 8);
adr[5] = (UCHAR) (driver_req_ptr ->nx_ip_driver_physical_address_lsw);
/* Get the CRC done. */
crc_val = nx_crc32(adr, NX_DRIVER_PHYSICAL_ADDRESS_SIZE);
/* Use only 6 MSbs to obtain value in range 0..63. */
crc_val >>= (32 - 6);
h_val = 63 - (int) crc_val ; /* pointer to 48 bit address */
if(nx_driver_information.nx_driver_information_multicast_count[h_val] == 1)
{
if (h_val < 32)
EXAMPLE_ENET->GALR &= ~(1 << h_val);
else
EXAMPLE_ENET->GAUR &= ~(1 << (h_val - 32));
}
else if(nx_driver_information.nx_driver_information_multicast_count[h_val] == 0)
{
return NX_NOT_SUCCESSFUL;
}
nx_driver_information.nx_driver_information_multicast_count[h_val]--;
/* Return success. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_get_status PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes hardware-specific get status requests. */
/* */
/* INPUT */
/* */
/* driver_req_ptr Driver request pointer */
/* */
/* OUTPUT */
/* */
/* status [NX_SUCCESS|NX_DRIVER_ERROR] */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_driver_get_status Driver get status processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static UINT _nx_driver_hardware_get_status(NX_IP_DRIVER *driver_req_ptr)
{
*(driver_req_ptr -> nx_ip_driver_return_ptr) = driver_req_ptr -> nx_ip_driver_interface -> nx_interface_link_up;
/* Return success. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_packet_transmitted PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes packets transmitted by the ethernet */
/* controller. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* nx_packet_transmit_release Release transmitted packet */
/* [_nx_driver_transmit_packet_dequeue] Optional transmit packet */
/* dequeue */
/* */
/* CALLED BY */
/* */
/* _nx_driver_deferred_processing Deferred driver processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_hardware_packet_transmitted(VOID)
{
ULONG numOfBuf = nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use;
ULONG idx = nx_driver_information.nx_driver_information_transmit_release_index;
/* Loop through buffers in use. */
while (numOfBuf--)
{
/* If no packet, just examine the next packet. */
if (nx_driver_information.nx_driver_information_transmit_packets[idx] == NX_NULL)
{
/* No packet in use, skip to next. */
idx = (idx + 1) & (NX_DRIVER_TX_DESCRIPTORS - 1);
continue;
}
/* Determine if the packet has been transmitted. */
if ((nx_driver_information.nx_driver_information_dma_tx_descriptors[idx].control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) == 0)
{
/* Yes, packet has been transmitted. */
/* Remove the Ethernet header and release the packet. */
NX_DRIVER_ETHERNET_HEADER_REMOVE(nx_driver_information.nx_driver_information_transmit_packets[idx]);
/* Release the packet. */
nx_packet_transmit_release(nx_driver_information.nx_driver_information_transmit_packets[idx]);
/* Clear the entry in the in-use array. */
nx_driver_information.nx_driver_information_transmit_packets[idx] = NX_NULL;
/* Update the transmit relesae index and number of buffers in use. */
idx = (idx + 1) & (NX_DRIVER_TX_DESCRIPTORS - 1);
nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use = numOfBuf;
nx_driver_information.nx_driver_information_transmit_release_index = idx;
}
else
{
/* Get out of the loop! */
break;
}
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_driver_hardware_packet_received PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes packets received by the ethernet */
/* controller. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_driver_transfer_to_netx Transfer packet to NetX */
/* nx_packet_allocate Allocate receive packets */
/* nx_packet_release Release receive packets */
/* */
/* CALLED BY */
/* */
/* _nx_driver_deferred_processing Deferred driver processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
static VOID _nx_driver_hardware_packet_received(VOID)
{
NX_PACKET *packet_ptr;
ULONG bd_count = 0;
INT i;
ULONG idx;
ULONG temp_idx;
ULONG first_idx = nx_driver_information.nx_driver_information_receive_current_index;
NX_PACKET *received_packet_ptr = nx_driver_information.nx_driver_information_receive_packets[first_idx];
/* Find out the BDs that owned by CPU. */
for (first_idx = idx = nx_driver_information.nx_driver_information_receive_current_index;
(nx_driver_information.nx_driver_information_dma_rx_descriptors[idx].control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) == 0;
idx = (idx + 1) & (NX_DRIVER_RX_DESCRIPTORS - 1))
{
/* Is the BD marked as the end of a frame? */
if (nx_driver_information.nx_driver_information_dma_rx_descriptors[idx].control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)
{
/* Yes, this BD is the last BD in the frame, set the last NX_PACKET's nx_packet_next to NULL. */
nx_driver_information.nx_driver_information_receive_packets[idx] -> nx_packet_next = NX_NULL;
/* Store the length of the packet in the first NX_PACKET. */
nx_driver_information.nx_driver_information_receive_packets[first_idx] -> nx_packet_length = (nx_driver_information.nx_driver_information_dma_rx_descriptors[idx].length) - 2;
nx_driver_information.nx_driver_information_receive_packets[first_idx] -> nx_packet_prepend_ptr += 2;
/* Adjust nx_packet_append_ptr with the size of the data in this buffer. */
nx_driver_information.nx_driver_information_receive_packets[idx] -> nx_packet_append_ptr = nx_driver_information.nx_driver_information_receive_packets[idx]->nx_packet_prepend_ptr
+ nx_driver_information.nx_driver_information_receive_packets[first_idx]->nx_packet_length
- bd_count * nx_driver_information.nx_driver_information_rx_buffer_size
+ (bd_count > 0 ? 2 : 0);
/* Allocate new NX_PACKETs for BDs. */
for (i = bd_count; i >= 0; i--)
{
temp_idx = (first_idx + i) & (NX_DRIVER_RX_DESCRIPTORS - 1);
/* Allocate a new packet from the packet pool. */
if (nx_packet_allocate(nx_driver_information.nx_driver_information_packet_pool_ptr, &packet_ptr,
NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS)
{
/* Adjust the new packet and assign it to the BD. */
nx_driver_information.nx_driver_information_dma_rx_descriptors[temp_idx].buffer = (uint8_t *)((uint32_t)packet_ptr->nx_packet_prepend_ptr);
nx_driver_information.nx_driver_information_dma_rx_descriptors[temp_idx].control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
nx_driver_information.nx_driver_information_receive_packets[temp_idx] = packet_ptr;
}
else
{
/* Allocation failed, get out of the loop. */
break;
}
}
if (i >= 0)
{
/* At least one packet allocation was failed, release the received packet. */
nx_packet_release(nx_driver_information.nx_driver_information_receive_packets[temp_idx] -> nx_packet_next);
for (; i >= 0; i--)
{
/* Free up the BD to ready state. */
temp_idx = (first_idx + i) & (NX_DRIVER_RX_DESCRIPTORS - 1);
nx_driver_information.nx_driver_information_dma_rx_descriptors[temp_idx].control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
nx_driver_information.nx_driver_information_receive_packets[temp_idx] -> nx_packet_prepend_ptr = nx_driver_information.nx_driver_information_receive_packets[temp_idx] -> nx_packet_data_start;
}
}
else
{
/* Transfer the packet to NetX. */
_nx_driver_transfer_to_netx(nx_driver_information.nx_driver_information_ip_ptr, received_packet_ptr);
}
/* Set the first BD index for the next packet. */
first_idx = (idx + 1) & (NX_DRIVER_RX_DESCRIPTORS - 1);
/* Update the current receive index. */
nx_driver_information.nx_driver_information_receive_current_index = first_idx;
received_packet_ptr = nx_driver_information.nx_driver_information_receive_packets[first_idx];
bd_count = 0;
}
else
{
/* This BD is not the last BD of a frame. It is a intermediate descriptor. */
nx_driver_information.nx_driver_information_receive_packets[idx] -> nx_packet_next = nx_driver_information.nx_driver_information_receive_packets[(idx + 1) & (NX_DRIVER_RX_DESCRIPTORS - 1)];
nx_driver_information.nx_driver_information_receive_packets[idx] -> nx_packet_append_ptr = nx_driver_information.nx_driver_information_receive_packets[idx] -> nx_packet_data_end;
bd_count++;
}
}
/* If Rx DMA is in suspended state, resume it. */
if (!EXAMPLE_ENET->RDAR)
{
/* Resume DMA reception */
EXAMPLE_ENET->RDAR = ENET_RDAR_RDAR_MASK;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* nx_driver_link_mode_changed PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function changes the link mode of the Ethernet. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* enet_duplex Set duplex mode */
/* nx_packet_transmit_release Release the packet */
/* */
/* CALLED BY */
/* */
/* nx_driver_ethernet_phy_isr */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
VOID nx_driver_link_mode_changed(VOID)
{
ULONG numOfBuf;
ULONG idx;
/* Stop the Ethernet. */
EXAMPLE_ENET->ECR &= ~ENET_ECR_ETHEREN_MASK;
/* Set speed for RMII mode. */
if (nx_driver_information.nx_driver_information_link_speed == kENET_MiiSpeed10M)
{
EXAMPLE_ENET->RCR |= ENET_RCR_RMII_10T_MASK;
}
else
{
EXAMPLE_ENET->RCR &= ~ENET_RCR_RMII_10T_MASK;
}
/* Set duplex mode. */
/* Set the duplex on the selected FEC controller*/
switch (nx_driver_information.nx_driver_information_link_duplex)
{
case kENET_MiiHalfDuplex:
EXAMPLE_ENET->RCR/*(ch)*/ |= ENET_RCR_DRT_MASK;
EXAMPLE_ENET->TCR/*(ch)*/ &= (uint32_t)~ENET_TCR_FDEN_MASK;
break;
case kENET_MiiFullDuplex:
default:
EXAMPLE_ENET->RCR/*(ch)*/ &= ~ENET_RCR_DRT_MASK;
EXAMPLE_ENET->TCR/*(ch)*/ |= ENET_TCR_FDEN_MASK;
break;
}
if (nx_driver_information.nx_driver_information_state >= NX_DRIVER_STATE_INITIALIZED)
{
numOfBuf = nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use;
idx = nx_driver_information.nx_driver_information_transmit_release_index;
/* Reset indices. */
nx_driver_information.nx_driver_information_receive_current_index = 0;
nx_driver_information.nx_driver_information_transmit_current_index = 0;
nx_driver_information.nx_driver_information_transmit_release_index = 0;
nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use = 0;
/* Release transmit packets if any. */
while (numOfBuf--)
{
/* If no packet, just examine the next packet. */
if (nx_driver_information.nx_driver_information_transmit_packets[idx] == NX_NULL)
{
/* No packet in use, skip to next. */
idx = (idx + 1) & (NX_DRIVER_TX_DESCRIPTORS - 1);
continue;
}
/* Remove the Ethernet header and release the packet. */
NX_DRIVER_ETHERNET_HEADER_REMOVE(nx_driver_information.nx_driver_information_transmit_packets[idx]);
/* Release the packet. */
nx_packet_transmit_release(nx_driver_information.nx_driver_information_transmit_packets[idx]);
}
/* Free receive descriptors. */
for (idx = 0; idx < NX_DRIVER_RX_DESCRIPTORS; idx++)
{
nx_driver_information.nx_driver_information_dma_rx_descriptors[idx].control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
}
}
/* Set Transmit Descriptor List Address Register */
EXAMPLE_ENET->TDSR = (ULONG) nx_driver_information.nx_driver_information_dma_tx_descriptors;
/* Configure the Receive Buffer Size Register. */
EXAMPLE_ENET->MRBR = nx_driver_information.nx_driver_information_rx_buffer_size;
/* Set Receive Descriptor List Address Register. */
EXAMPLE_ENET->RDSR = (ULONG) nx_driver_information.nx_driver_information_dma_rx_descriptors;
if (nx_driver_information.nx_driver_information_state >= NX_DRIVER_STATE_LINK_ENABLED)
{
/* Enable ethernet & start packet receiving. */
EXAMPLE_ENET->ECR |= ENET_ECR_ETHEREN_MASK;
EXAMPLE_ENET->RDAR = ENET_RDAR_RDAR_MASK;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* nx_driver_imx_ethernet_isr PORTABLE C */
/* 5.0 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processing incoming packets. This routine is */
/* be called from the receive packet ISR and assumes that the */
/* interrupt is saved/restored around the call by ThreadX. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_ip_driver_deferred_processing IP receive packet processing */
/* */
/* CALLED BY */
/* */
/* ISR */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 02-01-2018 Yuxin Zhou Initial Version 5.0 */
/* */
/**************************************************************************/
VOID nx_driver_imx_ethernet_isr(VOID)
{
UINT status;
status = EXAMPLE_ENET->EIR;
if(status & ENET_EIR_RXF_MASK )
{
/* Receive packet interrupt. */
#ifdef NX_DRIVER_ENABLE_DEFERRED
/* Set the receive packet interrupt. */
nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED;
#else
/* Process received packet(s). */
_nx_driver_hardware_packet_received();
#endif
#ifdef NX_DRIVER_ENABLE_DEFERRED
/* Call NetX deferred driver processing. */
_nx_ip_driver_deferred_processing(nx_driver_information.nx_driver_information_ip_ptr);
#endif
/* Clear the Ethernet DMA Rx IT pending bits */
EXAMPLE_ENET->EIR = ENET_EIR_RXF_MASK;
}
if(status & ENET_EIR_TXF_MASK)
{
EXAMPLE_ENET->TDAR = ENET_TDAR_TDAR_MASK;
#ifdef NX_DRIVER_ENABLE_DEFERRED
/* Set the transmit complete bit. */
nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED;
#else
/* Process transmitted packet(s). */
_nx_driver_hardware_packet_transmitted();
#endif
#ifdef NX_DRIVER_ENABLE_DEFERRED
/* Call NetX deferred driver processing. */
_nx_ip_driver_deferred_processing(nx_driver_information.nx_driver_information_ip_ptr);
#endif
/* Clear the Eth DMA Tx IT pending bit. */
EXAMPLE_ENET->EIR = ENET_EIR_TXF_MASK;
}
}
/****** DRIVER SPECIFIC ****** Start of part/vendor specific internal driver functions. */