forked from xuos/xiuos
add semc driver and eth driver
This commit is contained in:
parent
0340217e24
commit
1cf9939cb2
|
@ -70,6 +70,13 @@ int MountSDCard(void)
|
|||
#include <connect_sdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_SEMC
|
||||
extern status_t BOARD_InitSEMC(void);
|
||||
#ifdef BSP_USING_EXTSRAM
|
||||
extern int ExtSramInit(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void BOARD_SD_Pin_Config(uint32_t speed, uint32_t strength)
|
||||
{
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_00_USDHC1_CMD,
|
||||
|
@ -302,6 +309,22 @@ void InitBoardHardware()
|
|||
|
||||
InitBoardMemory((void *)HEAP_BEGIN, (void *)HEAP_END);
|
||||
|
||||
#ifdef BSP_USING_SEMC
|
||||
CLOCK_InitSysPfd(kCLOCK_Pfd2, 29);
|
||||
/* Set semc clock to 163.86 MHz */
|
||||
CLOCK_SetMux(kCLOCK_SemcMux, 1);
|
||||
CLOCK_SetDiv(kCLOCK_SemcDiv, 1);
|
||||
|
||||
if (BOARD_InitSEMC() != kStatus_Success) {
|
||||
KPrintf("\r\n SEMC Init Failed\r\n");
|
||||
}
|
||||
#ifdef MEM_EXTERN_SRAM
|
||||
else {
|
||||
ExtSramInit();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_LPUART
|
||||
Imxrt1052HwUartInit();
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,18 @@ menuconfig BSP_USING_GPIO
|
|||
source "$BSP_DIR/third_party_driver/gpio/Kconfig"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_LWIP
|
||||
bool "Using LwIP device"
|
||||
default n
|
||||
select RESOURCES_LWIP
|
||||
|
||||
menuconfig BSP_USING_SEMC
|
||||
bool "Using SEMC device"
|
||||
default n
|
||||
if BSP_USING_SEMC
|
||||
source "$BSP_DIR/third_party_driver/semc/Kconfig"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_SDIO
|
||||
bool "Using SD card device"
|
||||
default n
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
SRC_DIR := common gpio
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_LWIP),y)
|
||||
SRC_DIR += ethernet
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_SEMC),y)
|
||||
SRC_DIR += semc
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_LPUART),y)
|
||||
SRC_DIR += uart
|
||||
endif
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := enet_ethernetif.c enet_ethernetif_kinetis.c fsl_enet.c
|
||||
SRC_DIR := ksz8081
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2016, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file enet_ethernetif.c
|
||||
* @brief ethernet drivers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/ethip6.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp/pppoe.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
//#include "FreeRTOS.h"
|
||||
//#include "event_groups.h"
|
||||
#endif
|
||||
|
||||
#include "netif/ethernet.h"
|
||||
#include "enet_ethernetif.h"
|
||||
#include "enet_ethernetif_priv.h"
|
||||
|
||||
#include "fsl_enet.h"
|
||||
#include "fsl_phy.h"
|
||||
#include "fsl_gpio.h"
|
||||
#include "fsl_iomuxc.h"
|
||||
|
||||
#include "sys_arch.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
******************************************************************************/
|
||||
|
||||
void enet_delay(void)
|
||||
{
|
||||
volatile uint32_t i = 0;
|
||||
for (i = 0; i < 1000000; ++i)
|
||||
{
|
||||
__asm("NOP"); /* delay */
|
||||
}
|
||||
}
|
||||
|
||||
void Time_Update_LwIP(void)
|
||||
{
|
||||
}
|
||||
|
||||
void ethernetif_clk_init(void)
|
||||
{
|
||||
const clock_enet_pll_config_t config = {.enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1};
|
||||
CLOCK_InitEnetPll(&config);
|
||||
SysTick_Config(USEC_TO_COUNT(1000U, CLOCK_GetFreq(kCLOCK_CoreSysClk)));
|
||||
}
|
||||
|
||||
void ethernetif_gpio_init(void)
|
||||
{
|
||||
gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
|
||||
|
||||
IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true);
|
||||
|
||||
GPIO_PinInit(GPIO1, 3, &gpio_config);
|
||||
GPIO_PinInit(GPIO1, 10, &gpio_config);
|
||||
/* pull up the ENET_INT before RESET. */
|
||||
GPIO_WritePinOutput(GPIO1, 10, 1);
|
||||
GPIO_WritePinOutput(GPIO1, 3, 0);
|
||||
enet_delay();
|
||||
GPIO_WritePinOutput(GPIO1, 3, 1);
|
||||
}
|
||||
|
||||
void ETH_BSP_Config(void)
|
||||
{
|
||||
static int flag = 0;
|
||||
if(flag == 0)
|
||||
{
|
||||
ethernetif_clk_init();
|
||||
ethernetif_gpio_init();
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ethernetif_phy_init(struct ethernetif *ethernetif,
|
||||
const ethernetif_config_t *ethernetifConfig,
|
||||
enet_config_t *config)
|
||||
{
|
||||
uint32_t sysClock;
|
||||
status_t status;
|
||||
bool link = false;
|
||||
uint32_t count = 0;
|
||||
phy_speed_t speed;
|
||||
phy_duplex_t duplex;
|
||||
|
||||
sysClock = CLOCK_GetFreq(ethernetifConfig->clockName);
|
||||
|
||||
LWIP_PLATFORM_DIAG(("Initializing PHY...\r\n"));
|
||||
|
||||
while ((count < ENET_ATONEGOTIATION_TIMEOUT) && (!link))
|
||||
{
|
||||
status = PHY_Init(*ethernetif_enet_ptr(ethernetif), ethernetifConfig->phyAddress, sysClock);
|
||||
|
||||
if (kStatus_Success == status)
|
||||
{
|
||||
PHY_GetLinkStatus(*ethernetif_enet_ptr(ethernetif), ethernetifConfig->phyAddress, &link);
|
||||
}
|
||||
else if (kStatus_PHY_AutoNegotiateFail == status)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("PHY Auto-negotiation failed. Please check the ENET cable connection and link partner setting."));
|
||||
}
|
||||
else
|
||||
{
|
||||
LWIP_ASSERT("\r\nCannot initialize PHY.\r\n", 0);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (link)
|
||||
{
|
||||
/* Get the actual PHY link speed. */
|
||||
PHY_GetLinkSpeedDuplex(*ethernetif_enet_ptr(ethernetif), ethernetifConfig->phyAddress, &speed, &duplex);
|
||||
/* Change the MII speed and duplex for actual link status. */
|
||||
config->miiSpeed = (enet_mii_speed_t)speed;
|
||||
config->miiDuplex = (enet_mii_duplex_t)duplex;
|
||||
}
|
||||
#if 0 /* Disable assert. If initial auto-negation is timeout, \ \
|
||||
the ENET is set to default (100Mbs and full-duplex). */
|
||||
else
|
||||
{
|
||||
LWIP_ASSERT("\r\nGiving up PHY initialization. Please check the ENET cable connection and link partner setting and reset the board.\r\n", 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should be called when a packet is ready to be read
|
||||
* from the interface. It uses the function ethernetif_linkinput() that
|
||||
* should handle the actual reception of bytes from the network
|
||||
* interface. Then the type of the received packet is determined and
|
||||
* the appropriate input function is called.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
*/
|
||||
|
||||
void ethernetif_input(struct netif *netif)
|
||||
{
|
||||
struct pbuf *p;
|
||||
err_t ret = 0;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
/* move received packet into a new pbuf */
|
||||
while ((p = ethernetif_linkinput(netif)) != NULL)
|
||||
{
|
||||
/* pass all packets to ethernet_input, which decides what packets it supports */
|
||||
if ((ret = netif->input(p, netif)) != ERR_OK)
|
||||
{
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
|
||||
lw_print("lw: [%s] ret %d p %p\n", __func__, ret, p);
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ENET_Type *ethernetif_get_enet_base(const uint8_t enetIdx)
|
||||
{
|
||||
ENET_Type* enets[] = ENET_BASE_PTRS;
|
||||
int arrayIdx;
|
||||
int enetCount;
|
||||
|
||||
for (arrayIdx = 0, enetCount = 0; arrayIdx < ARRAY_SIZE(enets); arrayIdx++)
|
||||
{
|
||||
if (enets[arrayIdx] != 0U) /* process only defined positions */
|
||||
{ /* (some SOC headers count ENETs from 1 instead of 0) */
|
||||
if (enetCount == enetIdx)
|
||||
{
|
||||
return enets[arrayIdx];
|
||||
}
|
||||
enetCount++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err_t ethernetif_init(struct netif *netif, struct ethernetif *ethernetif,
|
||||
const uint8_t enetIdx,
|
||||
const ethernetif_config_t *ethernetifConfig)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
LWIP_ASSERT("ethernetifConfig != NULL", (ethernetifConfig != NULL));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwip";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
/*
|
||||
* Initialize the snmp variables and counters inside the struct netif.
|
||||
* The last argument should be replaced with your link speed, in units
|
||||
* of bits per second.
|
||||
*/
|
||||
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
|
||||
|
||||
netif->state = ethernetif;
|
||||
netif->name[0] = IFNAME0;
|
||||
netif->name[1] = IFNAME1;
|
||||
/* We directly use etharp_output() here to save a function call.
|
||||
* You can instead declare your own function an call etharp_output()
|
||||
* from it if you have to do some checks before sending (e.g. if link
|
||||
* is available...) */
|
||||
#if LWIP_IPV4
|
||||
netif->output = etharp_output;
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
netif->output_ip6 = ethip6_output;
|
||||
#endif /* LWIP_IPV6 */
|
||||
netif->linkoutput = ethernetif_linkoutput;
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IGMP
|
||||
netif_set_igmp_mac_filter(netif, ethernetif_igmp_mac_filter);
|
||||
netif->flags |= NETIF_FLAG_IGMP;
|
||||
#endif
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
netif_set_mld_mac_filter(netif, ethernetif_mld_mac_filter);
|
||||
netif->flags |= NETIF_FLAG_MLD6;
|
||||
#endif
|
||||
|
||||
/* Init ethernetif parameters.*/
|
||||
*ethernetif_enet_ptr(ethernetif) = ethernetif_get_enet_base(enetIdx);
|
||||
LWIP_ASSERT("*ethernetif_enet_ptr(ethernetif) != NULL", (*ethernetif_enet_ptr(ethernetif) != NULL));
|
||||
|
||||
/* set MAC hardware address length */
|
||||
netif->hwaddr_len = ETH_HWADDR_LEN;
|
||||
|
||||
/* set MAC hardware address */
|
||||
memcpy(netif->hwaddr, ethernetifConfig->macAddress, NETIF_MAX_HWADDR_LEN);
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500; /* TODO: define a config */
|
||||
|
||||
/* device capabilities */
|
||||
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
|
||||
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
|
||||
|
||||
/* ENET driver initialization.*/
|
||||
ethernetif_enet_init(netif, ethernetif, ethernetifConfig);
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/*
|
||||
* For hardware/netifs that implement MAC filtering.
|
||||
* All-nodes link-local is handled by default, so we must let the hardware know
|
||||
* to allow multicast packets in.
|
||||
* Should set mld_mac_filter previously. */
|
||||
if (netif->mld_mac_filter != NULL)
|
||||
{
|
||||
ip6_addr_t ip6_allnodes_ll;
|
||||
ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
|
||||
netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
|
||||
}
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,674 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2016, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file enet_ethernetif_kinetis.c
|
||||
* @brief ethernet drivers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include "sys_arch.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/ethip6.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp/pppoe.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
#ifdef FSL_RTOS_XIUOS
|
||||
#define USE_RTOS 1
|
||||
#define FSL_RTOS_FREE_RTOS
|
||||
#endif
|
||||
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
|
||||
#ifdef FSL_RTOS_XIUOS
|
||||
#include "xs_sem.h"
|
||||
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "event_groups.h"
|
||||
#include "list.h"
|
||||
#endif
|
||||
|
||||
typedef uint32_t TickType_t;
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||
|
||||
typedef TickType_t EventBits_t;
|
||||
|
||||
typedef long BaseType_t;
|
||||
typedef unsigned long UBaseType_t;
|
||||
|
||||
#define portBASE_TYPE long
|
||||
|
||||
#define pdFALSE ( ( BaseType_t ) 0 )
|
||||
#define pdTRUE ( ( BaseType_t ) 1 )
|
||||
|
||||
#define pdPASS ( pdTRUE )
|
||||
#define pdFAIL ( pdFALSE )
|
||||
|
||||
#ifndef FSL_RTOS_XIUOS
|
||||
typedef struct EventGroupDef_t
|
||||
{
|
||||
EventBits_t uxEventBits;
|
||||
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
UBaseType_t uxEventGroupNumber;
|
||||
#endif
|
||||
|
||||
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
|
||||
#endif
|
||||
} EventGroup_t;
|
||||
|
||||
struct EventGroupDef_t;
|
||||
typedef struct EventGroupDef_t * EventGroupHandle_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "enet_ethernetif.h"
|
||||
#include "enet_ethernetif_priv.h"
|
||||
|
||||
#include "fsl_enet.h"
|
||||
#include "fsl_phy.h"
|
||||
|
||||
#include "sys_arch.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Helper struct to hold private data used to operate your ethernet interface.
|
||||
*/
|
||||
struct ethernetif
|
||||
{
|
||||
ENET_Type *base;
|
||||
#if (defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)) || \
|
||||
(USE_RTOS && defined(FSL_RTOS_FREE_RTOS))
|
||||
enet_handle_t handle;
|
||||
#endif
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
|
||||
#ifdef FSL_RTOS_XIUOS
|
||||
int enetSemaphore;
|
||||
#else
|
||||
EventGroupHandle_t enetTransmitAccessEvent;
|
||||
#endif
|
||||
EventBits_t txFlag;
|
||||
#endif
|
||||
enet_rx_bd_struct_t *RxBuffDescrip;
|
||||
enet_tx_bd_struct_t *TxBuffDescrip;
|
||||
rx_buffer_t *RxDataBuff;
|
||||
tx_buffer_t *TxDataBuff;
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
******************************************************************************/
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
|
||||
int32 lwip_obtain_semaphore(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
return (KSemaphoreObtain(ethernetif->enetSemaphore, WAITING_FOREVER) == EOK);
|
||||
}
|
||||
|
||||
#if FSL_FEATURE_ENET_QUEUE > 1
|
||||
static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, uint32_t ringId, enet_event_t event, void *param)
|
||||
#else
|
||||
static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param)
|
||||
#endif /* FSL_FEATURE_ENET_QUEUE */
|
||||
{
|
||||
struct netif *netif = (struct netif *)param;
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
BaseType_t xResult;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case kENET_RxEvent:
|
||||
ethernetif_input(netif);
|
||||
break;
|
||||
case kENET_TxEvent:
|
||||
#ifndef FSL_RTOS_XIUOS
|
||||
{
|
||||
portBASE_TYPE taskToWake = pdFALSE;
|
||||
|
||||
#ifdef __CA7_REV
|
||||
if (SystemGetIRQNestingLevel())
|
||||
#else
|
||||
if (__get_IPSR())
|
||||
#endif
|
||||
{
|
||||
xResult = xEventGroupSetBitsFromISR(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, &taskToWake);
|
||||
if ((pdPASS == xResult) && (pdTRUE == taskToWake))
|
||||
{
|
||||
portYIELD_FROM_ISR(taskToWake);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xEventGroupSetBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
KSemaphoreAbandon(ethernetif->enetSemaphore);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IGMP
|
||||
err_t ethernetif_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group,
|
||||
enum netif_mac_filter_action action)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
uint8_t multicastMacAddr[6];
|
||||
err_t result;
|
||||
|
||||
multicastMacAddr[0] = 0x01U;
|
||||
multicastMacAddr[1] = 0x00U;
|
||||
multicastMacAddr[2] = 0x5EU;
|
||||
multicastMacAddr[3] = (group->addr >> 8) & 0x7FU;
|
||||
multicastMacAddr[4] = (group->addr >> 16) & 0xFFU;
|
||||
multicastMacAddr[5] = (group->addr >> 24) & 0xFFU;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case IGMP_ADD_MAC_FILTER:
|
||||
/* Adds the ENET device to a multicast group.*/
|
||||
ENET_AddMulticastGroup(ethernetif->base, multicastMacAddr);
|
||||
result = ERR_OK;
|
||||
break;
|
||||
case IGMP_DEL_MAC_FILTER:
|
||||
/*
|
||||
* Moves the ENET device from a multicast group.
|
||||
* Since the ENET_LeaveMulticastGroup() could filter out also other
|
||||
* group addresses having the same hash, the call is commented out.
|
||||
*/
|
||||
/* ENET_LeaveMulticastGroup(ethernetif->base, multicastMacAddr); */
|
||||
result = ERR_OK;
|
||||
break;
|
||||
default:
|
||||
result = ERR_IF;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group,
|
||||
enum netif_mac_filter_action action)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
uint8_t multicastMacAddr[6];
|
||||
err_t result;
|
||||
|
||||
multicastMacAddr[0] = 0x33U;
|
||||
multicastMacAddr[1] = 0x33U;
|
||||
multicastMacAddr[2] = (group->addr[3]) & 0xFFU;
|
||||
multicastMacAddr[3] = (group->addr[3] >> 8) & 0xFFU;
|
||||
multicastMacAddr[4] = (group->addr[3] >> 16) & 0xFFU;
|
||||
multicastMacAddr[5] = (group->addr[3] >> 24) & 0xFFU;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case NETIF_ADD_MAC_FILTER:
|
||||
/* Adds the ENET device to a multicast group.*/
|
||||
ENET_AddMulticastGroup(ethernetif->base, multicastMacAddr);
|
||||
result = ERR_OK;
|
||||
break;
|
||||
case NETIF_DEL_MAC_FILTER:
|
||||
/*
|
||||
* Moves the ENET device from a multicast group.
|
||||
* Since the ENET_LeaveMulticastGroup() could filter out also other
|
||||
* group addresses having the same hash, the call is commented out.
|
||||
*/
|
||||
/* ENET_LeaveMulticastGroup(ethernetif->base, multicastMacAddr); */
|
||||
result = ERR_OK;
|
||||
break;
|
||||
default:
|
||||
result = ERR_IF;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes ENET driver.
|
||||
*/
|
||||
void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif,
|
||||
const ethernetif_config_t *ethernetifConfig)
|
||||
{
|
||||
enet_config_t config;
|
||||
uint32_t sysClock;
|
||||
enet_buffer_config_t buffCfg[ENET_RING_NUM];
|
||||
|
||||
/* prepare the buffer configuration. */
|
||||
buffCfg[0].rxBdNumber = ENET_RXBD_NUM; /* Receive buffer descriptor number. */
|
||||
buffCfg[0].txBdNumber = ENET_TXBD_NUM; /* Transmit buffer descriptor number. */
|
||||
buffCfg[0].rxBuffSizeAlign = sizeof(rx_buffer_t); /* Aligned receive data buffer size. */
|
||||
buffCfg[0].txBuffSizeAlign = sizeof(tx_buffer_t); /* Aligned transmit data buffer size. */
|
||||
buffCfg[0].rxBdStartAddrAlign = &(ethernetif->RxBuffDescrip[0]); /* Aligned receive buffer descriptor start address. */
|
||||
buffCfg[0].txBdStartAddrAlign = &(ethernetif->TxBuffDescrip[0]); /* Aligned transmit buffer descriptor start address. */
|
||||
buffCfg[0].rxBufferAlign = &(ethernetif->RxDataBuff[0][0]); /* Receive data buffer start address. */
|
||||
buffCfg[0].txBufferAlign = &(ethernetif->TxDataBuff[0][0]); /* Transmit data buffer start address. */
|
||||
|
||||
sysClock = CLOCK_GetFreq(ethernetifConfig->clockName);
|
||||
|
||||
ENET_GetDefaultConfig(&config);
|
||||
config.ringNum = ENET_RING_NUM;
|
||||
|
||||
ethernetif_phy_init(ethernetif, ethernetifConfig, &config);
|
||||
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
uint32_t instance;
|
||||
static ENET_Type *const enetBases[] = ENET_BASE_PTRS;
|
||||
static const IRQn_Type enetTxIrqId[] = ENET_Transmit_IRQS;
|
||||
/*! @brief Pointers to enet receive IRQ number for each instance. */
|
||||
static const IRQn_Type enetRxIrqId[] = ENET_Receive_IRQS;
|
||||
#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
|
||||
/*! @brief Pointers to enet timestamp IRQ number for each instance. */
|
||||
static const IRQn_Type enetTsIrqId[] = ENET_1588_Timer_IRQS;
|
||||
#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
|
||||
|
||||
/* Create the Event for transmit busy release trigger. */
|
||||
#ifdef FSL_RTOS_XIUOS
|
||||
if(ethernetif->enetSemaphore < 0)
|
||||
{
|
||||
ethernetif->enetSemaphore = KSemaphoreCreate(0);
|
||||
}
|
||||
#else
|
||||
ethernetif->enetTransmitAccessEvent = xEventGroupCreate();
|
||||
#endif
|
||||
ethernetif->txFlag = 0x1;
|
||||
|
||||
config.interrupt |= kENET_RxFrameInterrupt | kENET_TxFrameInterrupt | kENET_TxBufferInterrupt;
|
||||
|
||||
for (instance = 0; instance < ARRAY_SIZE(enetBases); instance++)
|
||||
{
|
||||
if (enetBases[instance] == ethernetif->base)
|
||||
{
|
||||
#ifdef __CA7_REV
|
||||
GIC_SetPriority(enetRxIrqId[instance], ENET_PRIORITY);
|
||||
GIC_SetPriority(enetTxIrqId[instance], ENET_PRIORITY);
|
||||
#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
|
||||
GIC_SetPriority(enetTsIrqId[instance], ENET_1588_PRIORITY);
|
||||
#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
|
||||
#else
|
||||
NVIC_SetPriority(enetRxIrqId[instance], ENET_PRIORITY);
|
||||
NVIC_SetPriority(enetTxIrqId[instance], ENET_PRIORITY);
|
||||
#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
|
||||
NVIC_SetPriority(enetTsIrqId[instance], ENET_1588_PRIORITY);
|
||||
#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
|
||||
#endif /* __CA7_REV */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LWIP_ASSERT("Input Ethernet base error!", (instance != ARRAY_SIZE(enetBases)));
|
||||
#endif /* USE_RTOS */
|
||||
|
||||
/* Initialize the ENET module.*/
|
||||
ENET_Init(ethernetif->base, ðernetif->handle, &config, &buffCfg[0], netif->hwaddr, sysClock);
|
||||
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
ENET_SetCallback(ðernetif->handle, ethernet_callback, netif);
|
||||
#endif
|
||||
|
||||
ENET_ActiveRead(ethernetif->base);
|
||||
// low_level_init();
|
||||
}
|
||||
|
||||
ENET_Type **ethernetif_enet_ptr(struct ethernetif *ethernetif)
|
||||
{
|
||||
return &(ethernetif->base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next buffer for TX.
|
||||
* Can wait if no buffer available.
|
||||
*/
|
||||
static unsigned char *enet_get_tx_buffer(struct ethernetif *ethernetif)
|
||||
{
|
||||
static unsigned char ucBuffer[ENET_FRAME_MAX_FRAMELEN];
|
||||
return ucBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends frame via ENET.
|
||||
*/
|
||||
static err_t enet_send_frame(struct ethernetif *ethernetif, unsigned char *data, const uint32_t length)
|
||||
{
|
||||
#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS)
|
||||
{
|
||||
status_t result;
|
||||
|
||||
lw_print("lw: [%s] len %d\n", __func__, length);
|
||||
|
||||
do
|
||||
{
|
||||
result = ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length);
|
||||
|
||||
if (result == kStatus_ENET_TxFrameBusy)
|
||||
{
|
||||
#ifdef FSL_RTOS_XIUOS
|
||||
KSemaphoreObtain(ethernetif->enetSemaphore, portMAX_DELAY);
|
||||
#else
|
||||
xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, pdTRUE, (BaseType_t) false,
|
||||
portMAX_DELAY);
|
||||
#endif
|
||||
}
|
||||
|
||||
} while (result == kStatus_ENET_TxFrameBusy);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
#else
|
||||
{
|
||||
uint32_t counter;
|
||||
|
||||
for (counter = ENET_TIMEOUT; counter != 0U; counter--)
|
||||
{
|
||||
if (ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length) != kStatus_ENET_TxFrameBusy)
|
||||
{
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct pbuf *ethernetif_linkinput(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf *q;
|
||||
uint32_t len;
|
||||
status_t status;
|
||||
|
||||
/* Obtain the size of the packet and put it into the "len"
|
||||
variable. */
|
||||
status = ENET_GetRxFrameSize(ðernetif->handle, &len);
|
||||
|
||||
if (kStatus_ENET_RxFrameEmpty != status)
|
||||
{
|
||||
/* Call ENET_ReadFrame when there is a received frame. */
|
||||
if (len != 0)
|
||||
{
|
||||
#if ETH_PAD_SIZE
|
||||
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
|
||||
#endif
|
||||
|
||||
/* We allocate a pbuf chain of pbufs from the pool. */
|
||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
|
||||
#endif
|
||||
if (p->next == 0) /* One-chain buffer.*/
|
||||
{
|
||||
ENET_ReadFrame(ethernetif->base, ðernetif->handle, p->payload, p->len);
|
||||
}
|
||||
else /* Multi-chain buffer.*/
|
||||
{
|
||||
uint8_t data_tmp[ENET_FRAME_MAX_FRAMELEN];
|
||||
uint32_t data_tmp_len = 0;
|
||||
|
||||
ENET_ReadFrame(ethernetif->base, ðernetif->handle, data_tmp, p->tot_len);
|
||||
|
||||
/* We iterate over the pbuf chain until we have read the entire
|
||||
* packet into the pbuf. */
|
||||
for (q = p; (q != NULL) && ((data_tmp_len + q->len) <= sizeof(data_tmp)); q = q->next)
|
||||
{
|
||||
/* Read enough bytes to fill this pbuf in the chain. The
|
||||
* available data in the pbuf is given by the q->len
|
||||
* variable. */
|
||||
memcpy(q->payload, &data_tmp[data_tmp_len], q->len);
|
||||
data_tmp_len += q->len;
|
||||
}
|
||||
}
|
||||
|
||||
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
|
||||
if (((u8_t *)p->payload)[0] & 1)
|
||||
{
|
||||
/* broadcast or multicast packet*/
|
||||
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast packet*/
|
||||
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
|
||||
}
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
LINK_STATS_INC(link.recv);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drop packet*/
|
||||
ENET_ReadFrame(ethernetif->base, ðernetif->handle, NULL, 0U);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: Fail to allocate new memory space\n"));
|
||||
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
MIB2_STATS_NETIF_INC(netif, ifindiscards);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update the received buffer when error happened. */
|
||||
if (status == kStatus_ENET_RxFrameError)
|
||||
{
|
||||
#if 0 && defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) /* Error statisctics */
|
||||
enet_data_error_stats_t eErrStatic;
|
||||
/* Get the error information of the received g_frame. */
|
||||
ENET_GetRxErrBeforeReadFrame(ðernetif->handle, &eErrStatic);
|
||||
#endif
|
||||
/* Update the receive buffer. */
|
||||
ENET_ReadFrame(ethernetif->base, ðernetif->handle, NULL, 0U);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: RxFrameError\n"));
|
||||
|
||||
LINK_STATS_INC(link.drop);
|
||||
MIB2_STATS_NETIF_INC(netif, ifindiscards);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
err_t result;
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
struct pbuf *q;
|
||||
unsigned char *pucBuffer;
|
||||
unsigned char *pucChar;
|
||||
|
||||
LWIP_ASSERT("Output packet buffer empty", p);
|
||||
|
||||
pucBuffer = enet_get_tx_buffer(ethernetif);
|
||||
if (pucBuffer == NULL)
|
||||
{
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* Initiate transfer. */
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
|
||||
#endif
|
||||
|
||||
if (p->len == p->tot_len)
|
||||
{
|
||||
/* No pbuf chain, don't have to copy -> faster. */
|
||||
pucBuffer = (unsigned char *)p->payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pbuf chain, copy into contiguous ucBuffer. */
|
||||
if (p->tot_len > ENET_FRAME_MAX_FRAMELEN)
|
||||
{
|
||||
return ERR_BUF;
|
||||
}
|
||||
else
|
||||
{
|
||||
pucChar = pucBuffer;
|
||||
|
||||
for (q = p; q != NULL; q = q->next)
|
||||
{
|
||||
/* Send the data from the pbuf to the interface, one pbuf at a
|
||||
time. The size of the data in each pbuf is kept in the ->len
|
||||
variable. */
|
||||
/* send data from(q->payload, q->len); */
|
||||
memcpy(pucChar, q->payload, q->len);
|
||||
pucChar += q->len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send frame. */
|
||||
result = enet_send_frame(ethernetif, pucBuffer, p->tot_len);
|
||||
|
||||
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
|
||||
if (((u8_t *)p->payload)[0] & 1)
|
||||
{
|
||||
/* broadcast or multicast packet*/
|
||||
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast packet */
|
||||
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
|
||||
}
|
||||
/* increase ifoutdiscards or ifouterrors on error */
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* first network interface. It calls the function ethernetif_init() to do the
|
||||
* actual setup of the hardware.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t ethernetif0_init(struct netif *netif)
|
||||
{
|
||||
static struct ethernetif ethernetif_0;
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rxBuffDescrip_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t txBuffDescrip_0[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
SDK_ALIGN(static rx_buffer_t rxDataBuff_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
SDK_ALIGN(static tx_buffer_t txDataBuff_0[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
|
||||
ethernetif_0.RxBuffDescrip = &(rxBuffDescrip_0[0]);
|
||||
ethernetif_0.TxBuffDescrip = &(txBuffDescrip_0[0]);
|
||||
ethernetif_0.RxDataBuff = &(rxDataBuff_0[0]);
|
||||
ethernetif_0.TxDataBuff = &(txDataBuff_0[0]);
|
||||
|
||||
return ethernetif_init(netif, ðernetif_0, 0U, (ethernetif_config_t *)netif->state);
|
||||
}
|
||||
|
||||
#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 1)
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* second network interface. It calls the function ethernetif_init() to do the
|
||||
* actual setup of the hardware.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t ethernetif1_init(struct netif *netif)
|
||||
{
|
||||
static struct ethernetif ethernetif_1;
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rxBuffDescrip_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t txBuffDescrip_1[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
SDK_ALIGN(static rx_buffer_t rxDataBuff_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
SDK_ALIGN(static tx_buffer_t txDataBuff_1[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
|
||||
ethernetif_1.RxBuffDescrip = &(rxBuffDescrip_1[0]);
|
||||
ethernetif_1.TxBuffDescrip = &(txBuffDescrip_1[0]);
|
||||
ethernetif_1.RxDataBuff = &(rxDataBuff_1[0]);
|
||||
ethernetif_1.TxDataBuff = &(txDataBuff_1[0]);
|
||||
|
||||
return ethernetif_init(netif, ðernetif_1, 1U, (ethernetif_config_t *)netif->state);
|
||||
}
|
||||
#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */
|
960
Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_lpc.c
Executable file
960
Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_lpc.c
Executable file
|
@ -0,0 +1,960 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2016, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file enet_ethernetif_lpc.c
|
||||
* @brief ethernet drivers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/ethip6.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp/pppoe.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
//#if !NO_SYS
|
||||
//#include "FreeRTOS.h"
|
||||
//#include "event_groups.h"
|
||||
//#include "lwip/tcpip.h"
|
||||
//#endif /* !NO_SYS */
|
||||
|
||||
#include "enet_ethernetif.h"
|
||||
#include "enet_ethernetif_priv.h"
|
||||
|
||||
#include "fsl_enet.h"
|
||||
#include "fsl_phy.h"
|
||||
|
||||
//#if MEM_ALIGNMENT != FSL_ENET_BUFF_ALIGNMENT
|
||||
///* These two has to match for zero-copy functionality */
|
||||
//#error "MEM_ALIGNMENT != FSL_ENET_BUFF_ALIGNMENT"
|
||||
//#endif /* MEM_ALIGNMENT != FSL_ENET_BUFF_ALIGNMENT */
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Used to wrap received data in a pbuf to be passed into lwIP
|
||||
* without copying.
|
||||
* Once last reference is released, RX descriptor will be returned to DMA.
|
||||
*/
|
||||
typedef struct rx_pbuf_wrapper
|
||||
{
|
||||
struct pbuf_custom p; /*!< Pbuf wrapper. Has to be first. */
|
||||
enet_rx_bd_struct_t* rxDesc; /*!< Descriptor holding the data. */
|
||||
struct ethernetif *ethernetif; /*!< Ethernet interface context data. */
|
||||
volatile bool ownedByLwip; /*!< If true, descriptor cannot be reused by DMA yet. */
|
||||
} rx_pbuf_wrapper_t;
|
||||
|
||||
/*!
|
||||
* @brief Helper struct to hold private data used to operate
|
||||
* your ethernet interface.
|
||||
*/
|
||||
struct ethernetif
|
||||
{
|
||||
ENET_Type *base;
|
||||
enet_handle_t handle;
|
||||
#if !NO_SYS
|
||||
EventGroupHandle_t enetTransmitAccessEvent;
|
||||
EventBits_t txFlag;
|
||||
#endif /* !NO_SYS */
|
||||
enet_rx_bd_struct_t *RxBuffDescrip;
|
||||
enet_tx_bd_struct_t *TxBuffDescrip;
|
||||
rx_buffer_t *RxDataBuff;
|
||||
volatile struct pbuf *txPbufs[ENET_TXBD_NUM];
|
||||
volatile uint8_t txIdx;
|
||||
volatile uint8_t txReleaseIdx;
|
||||
rx_pbuf_wrapper_t rxPbufs[ENET_RXBD_NUM];
|
||||
uint8_t rxIdx;
|
||||
const mem_range_t *non_dma_memory;
|
||||
};
|
||||
|
||||
static void ethernetif_tx_release(struct ethernetif *ethernetif);
|
||||
static void ethernetif_rx_release(struct pbuf *p);
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Called from ENET ISR.
|
||||
*/
|
||||
static void ethernet_callback(ENET_Type *base, enet_handle_t *handle,
|
||||
enet_event_t event, uint8_t channel, void *param)
|
||||
#if NO_SYS
|
||||
{
|
||||
struct netif *netif = (struct netif *)param;
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
|
||||
if (event == kENET_TxIntEvent)
|
||||
{
|
||||
ethernetif_tx_release(ethernetif);
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct netif *netif = (struct netif *)param;
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
BaseType_t xResult;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case kENET_RxIntEvent:
|
||||
ethernetif_input(netif);
|
||||
break;
|
||||
case kENET_TxIntEvent:
|
||||
{
|
||||
portBASE_TYPE taskToWake = pdFALSE;
|
||||
|
||||
ethernetif_tx_release(ethernetif);
|
||||
|
||||
#ifdef __CA7_REV
|
||||
if (SystemGetIRQNestingLevel())
|
||||
#else
|
||||
if (__get_IPSR())
|
||||
#endif
|
||||
{
|
||||
xResult = xEventGroupSetBitsFromISR(
|
||||
ethernetif->enetTransmitAccessEvent,
|
||||
ethernetif->txFlag, &taskToWake);
|
||||
if ((pdPASS == xResult) && (pdTRUE == taskToWake))
|
||||
{
|
||||
portYIELD_FROM_ISR(taskToWake);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xEventGroupSetBits(ethernetif->enetTransmitAccessEvent,
|
||||
ethernetif->txFlag);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* NO_SYS */
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IGMP
|
||||
err_t ethernetif_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group,
|
||||
enum netif_mac_filter_action action)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
err_t result;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case IGMP_ADD_MAC_FILTER:
|
||||
/* LPC ENET does not accept multicast selectively,
|
||||
* so all multicast has to be passed through. */
|
||||
ENET_AcceptAllMulticast(ethernetif->base);
|
||||
result = ERR_OK;
|
||||
break;
|
||||
case IGMP_DEL_MAC_FILTER:
|
||||
/*
|
||||
* Moves the ENET device from a multicast group.
|
||||
* Since we don't keep track of which multicast groups
|
||||
* are still to enabled, the call is commented out.
|
||||
*/
|
||||
/* ENET_RejectAllMulticast(ethernetif->base); */
|
||||
result = ERR_OK;
|
||||
break;
|
||||
default:
|
||||
result = ERR_IF;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group,
|
||||
enum netif_mac_filter_action action)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
err_t result;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case NETIF_ADD_MAC_FILTER:
|
||||
/* LPC ENET does not accept multicast selectively,
|
||||
* so all multicast has to be passed through. */
|
||||
ENET_AcceptAllMulticast(ethernetif->base);
|
||||
result = ERR_OK;
|
||||
break;
|
||||
case NETIF_DEL_MAC_FILTER:
|
||||
/*
|
||||
* Moves the ENET device from a multicast group.
|
||||
* Since we don't keep track of which multicast groups
|
||||
* are still to enabled, the call is commented out.
|
||||
*/
|
||||
/* ENET_RejectAllMulticast(ethernetif->base); */
|
||||
result = ERR_OK;
|
||||
break;
|
||||
default:
|
||||
result = ERR_IF;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the RX descriptor by its index.
|
||||
*/
|
||||
static inline enet_rx_bd_struct_t *ethernetif_get_rx_desc(
|
||||
struct ethernetif *ethernetif,
|
||||
uint32_t index)
|
||||
{
|
||||
return &(ethernetif->RxBuffDescrip[index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TX descriptor by its index.
|
||||
*/
|
||||
static inline enet_tx_bd_struct_t *ethernetif_get_tx_desc(
|
||||
struct ethernetif *ethernetif,
|
||||
uint32_t index)
|
||||
{
|
||||
return &(ethernetif->TxBuffDescrip[index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes ENET driver.
|
||||
*/
|
||||
void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif,
|
||||
const ethernetif_config_t *ethernetifConfig)
|
||||
{
|
||||
enet_config_t config;
|
||||
uint32_t sysClock;
|
||||
enet_buffer_config_t buffCfg[ENET_RING_NUM];
|
||||
uint32_t rxBufferStartAddr[ENET_RXBD_NUM];
|
||||
uint32_t i;
|
||||
|
||||
/* calculate start addresses of all rx buffers */
|
||||
for (i = 0; i < ENET_RXBD_NUM; i++)
|
||||
{
|
||||
rxBufferStartAddr[i] = (uint32_t)&(ethernetif->RxDataBuff[i][ETH_PAD_SIZE]);
|
||||
}
|
||||
|
||||
/* prepare the buffer configuration. */
|
||||
buffCfg[0].rxRingLen = ENET_RXBD_NUM; /* The length of receive buffer descriptor ring. */
|
||||
buffCfg[0].txRingLen = ENET_TXBD_NUM; /* The length of transmit buffer descriptor ring. */
|
||||
buffCfg[0].txDescStartAddrAlign = ethernetif_get_tx_desc(ethernetif, 0U); /* Aligned transmit descriptor start address. */
|
||||
buffCfg[0].txDescTailAddrAlign = ethernetif_get_tx_desc(ethernetif, 0U); /* Aligned transmit descriptor tail address. */
|
||||
buffCfg[0].rxDescStartAddrAlign = ethernetif_get_rx_desc(ethernetif, 0U); /* Aligned receive descriptor start address. */
|
||||
buffCfg[0].rxDescTailAddrAlign = ethernetif_get_rx_desc(ethernetif, ENET_RXBD_NUM); /* Aligned receive descriptor tail address. */
|
||||
buffCfg[0].rxBufferStartAddr = rxBufferStartAddr; /* Start addresses of the rx buffers. */
|
||||
buffCfg[0].rxBuffSizeAlign = sizeof(rx_buffer_t); /* Aligned receive data buffer size. */
|
||||
|
||||
sysClock = CLOCK_GetFreq(ethernetifConfig->clockName);
|
||||
|
||||
LWIP_ASSERT("ethernetifConfig->non_dma_memory == NULL", (ethernetifConfig->non_dma_memory != NULL));
|
||||
ethernetif->non_dma_memory = ethernetifConfig->non_dma_memory;
|
||||
|
||||
ENET_GetDefaultConfig(&config);
|
||||
config.multiqueueCfg = NULL;
|
||||
|
||||
ethernetif_phy_init(ethernetif, ethernetifConfig, &config);
|
||||
|
||||
#if !NO_SYS
|
||||
/* Create the Event for transmit busy release trigger. */
|
||||
ethernetif->enetTransmitAccessEvent = xEventGroupCreate();
|
||||
ethernetif->txFlag = 0x1;
|
||||
#endif /* !NO_SYS */
|
||||
NVIC_SetPriority(ETHERNET_IRQn, ENET_PRIORITY);
|
||||
|
||||
ethernetif->txIdx = 0U;
|
||||
ethernetif->rxIdx = 0U;
|
||||
ethernetif->txReleaseIdx = 0U;
|
||||
|
||||
for (i = 0; i < ENET_RXBD_NUM; i++)
|
||||
{
|
||||
ethernetif->rxPbufs[i].p.custom_free_function = ethernetif_rx_release;
|
||||
ethernetif->rxPbufs[i].rxDesc = ðernetif->RxBuffDescrip[i];
|
||||
ethernetif->rxPbufs[i].ethernetif = ethernetif;
|
||||
ethernetif->rxPbufs[i].ownedByLwip = false;
|
||||
}
|
||||
|
||||
ENET_Init(ethernetif->base, &config, netif->hwaddr, sysClock);
|
||||
|
||||
#if defined(LPC54018_SERIES)
|
||||
/* Workaround for receive issue on lpc54018 */
|
||||
ethernetif->base->MAC_FRAME_FILTER |= ENET_MAC_FRAME_FILTER_RA_MASK;
|
||||
#endif
|
||||
|
||||
/* Create the handler. */
|
||||
#if NO_SYS
|
||||
ENET_EnableInterrupts(ethernetif->base, kENET_DmaTx);
|
||||
#else
|
||||
ENET_EnableInterrupts(ethernetif->base, kENET_DmaTx | kENET_DmaRx);
|
||||
#endif /* NO_SYS */
|
||||
ENET_CreateHandler(ethernetif->base, ðernetif->handle, &config,
|
||||
&buffCfg[0], ethernet_callback, netif);
|
||||
|
||||
ENET_DescriptorInit(ethernetif->base, &config, &buffCfg[0]);
|
||||
|
||||
/* Active TX/RX. */
|
||||
ENET_StartRxTx(ethernetif->base, 1, 1);
|
||||
}
|
||||
|
||||
ENET_Type **ethernetif_enet_ptr(struct ethernetif *ethernetif)
|
||||
{
|
||||
return &(ethernetif->base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ENET instance index from its base address.
|
||||
*/
|
||||
static uint32_t ethernetif_get_enet_idx(ENET_Type *base)
|
||||
{
|
||||
static ENET_Type *const s_enetBases[] = ENET_BASE_PTRS;
|
||||
uint32_t instance;
|
||||
|
||||
for (instance = 0; instance < FSL_FEATURE_SOC_LPC_ENET_COUNT; instance++)
|
||||
{
|
||||
if (s_enetBases[instance] == base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LWIP_ASSERT("Cannot find ENET instance index from its base address.",
|
||||
instance < FSL_FEATURE_SOC_LPC_ENET_COUNT);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends (part of) a frame via ENET.
|
||||
* TODO: Since ENET_SendFrame() could not be used, some functionality it does
|
||||
* is missing here for now (channel selection depending on AVB content,
|
||||
* timestamping.
|
||||
*/
|
||||
static void ethernetif_send_buffer(struct ethernetif *ethernetif,
|
||||
unsigned char *data,
|
||||
const uint32_t length,
|
||||
struct pbuf *p_to_release,
|
||||
enet_desc_flag flag)
|
||||
{
|
||||
static const IRQn_Type s_enetIrqId[] = ENET_IRQS;
|
||||
enet_tx_bd_struct_t *txDesc = ethernetif_get_tx_desc(ethernetif,
|
||||
ethernetif->txIdx);
|
||||
ethernetif->txPbufs[ethernetif->txIdx] = p_to_release;
|
||||
ethernetif->txIdx = (ethernetif->txIdx + 1) % ENET_TXBD_NUM;
|
||||
|
||||
/* Prepare the descriptor for transmit. */
|
||||
txDesc->buff1Addr = (uint32_t)data;
|
||||
txDesc->buff2Addr = (uint32_t)NULL;
|
||||
txDesc->buffLen =
|
||||
ENET_TXDESCRIP_RD_BL1(length) | ENET_TXDESCRIP_RD_IOC_MASK;
|
||||
|
||||
txDesc->controlStat =
|
||||
ENET_TXDESCRIP_RD_FL(length) | ENET_TXDESCRIP_RD_LDFD(flag);
|
||||
if ((flag & kENET_FirstFlagOnly) == 0)
|
||||
{
|
||||
/*
|
||||
* Submit to DMA if not the first descriptor in chain.
|
||||
* All the descriptors have to be prepared before the first one
|
||||
* is flagged for DMA and transfer starts. ENET could output invalid
|
||||
* frames otherwise (the exception is Store and Forward mode, where
|
||||
* delays between preparing of descriptors does not matter).
|
||||
*/
|
||||
txDesc->controlStat |= ENET_TXDESCRIP_RD_OWN_MASK;
|
||||
}
|
||||
|
||||
enet_tx_bd_ring_t *txBdRing = (enet_tx_bd_ring_t *)
|
||||
ðernetif->handle.txBdRing[0];
|
||||
|
||||
/*
|
||||
* Increment txDescUsed.
|
||||
* Without this, callback would not fire from ENET ISR on finished TX.
|
||||
* This is kind of a hack. Alternative could be to define
|
||||
* void ETHERNET_DriverIRQHandler(void) and handle IRQs completely
|
||||
* in this file.
|
||||
*/
|
||||
DisableIRQ(s_enetIrqId[ethernetif_get_enet_idx(ethernetif->base)]);
|
||||
txBdRing->txDescUsed++;
|
||||
EnableIRQ(s_enetIrqId[ethernetif_get_enet_idx(ethernetif->base)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaims exactly one TX descriptor after its data has been sent out.
|
||||
* Then the descriptor can be used by application to prepare next data to send.
|
||||
*/
|
||||
static void ethernetif_tx_release(struct ethernetif *ethernetif)
|
||||
{
|
||||
LWIP_ASSERT("Attempt to release more TX buffers than acquired.",
|
||||
ethernetif->txIdx != ethernetif->txReleaseIdx);
|
||||
enet_tx_bd_struct_t *txDesc
|
||||
= ðernetif->TxBuffDescrip[ethernetif->txReleaseIdx];
|
||||
LWIP_ASSERT("TX buffer still owned by DMA.",
|
||||
!ENET_IsTxDescriptorDmaOwn(txDesc));
|
||||
|
||||
struct pbuf *p = (struct pbuf *)
|
||||
ethernetif->txPbufs[ethernetif->txReleaseIdx];
|
||||
if (p != NULL)
|
||||
{
|
||||
#if ETH_PAD_SIZE
|
||||
/* Reclaim the padding, force because it may be REF pbuf. */
|
||||
pbuf_header_force(p, ETH_PAD_SIZE);
|
||||
#endif
|
||||
|
||||
#if NO_SYS
|
||||
#if defined(LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT) && LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
pbuf_free(p);
|
||||
#else
|
||||
#error "Bare metal requires LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT=1 because pbuf_free() is being called from an ISR"
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
#else
|
||||
if (pbuf_free_callback(p) != ERR_OK)
|
||||
{
|
||||
#if defined(LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT) && LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
pbuf_free(p);
|
||||
#else
|
||||
LWIP_ASSERT("Failed to enqueue pbuf deallocation on tcpip_thread",
|
||||
0);
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
}
|
||||
#endif /* NO_SYS */
|
||||
|
||||
ethernetif->txPbufs[ethernetif->txReleaseIdx] = NULL;
|
||||
}
|
||||
|
||||
ethernetif->txReleaseIdx = (ethernetif->txReleaseIdx + 1) % ENET_TXBD_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaims RX descriptor which holds the p's buffer after p is no longer used
|
||||
* by the application / lwIP. The DMA can receive new data into
|
||||
* the descriptor's buffer then.
|
||||
* Note that RX buffers may be freed by lwIP out of the order in which they were
|
||||
* passed to lwIP. Therefore there may be spaces between the RX descriptors
|
||||
* flagged as owned by DMA and DMA could still wait until it's actual position
|
||||
* is released.
|
||||
*/
|
||||
static void ethernetif_rx_release(struct pbuf *p)
|
||||
{
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
rx_pbuf_wrapper_t *wrapper = (rx_pbuf_wrapper_t *)p;
|
||||
#if NO_SYS
|
||||
bool intEnable = false;
|
||||
#else
|
||||
bool intEnable = true;
|
||||
#endif /* NO_SYS */
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
|
||||
wrapper->ownedByLwip = false;
|
||||
|
||||
/* Update the receive buffer descriptor. */
|
||||
ENET_UpdateRxDescriptor(wrapper->rxDesc, NULL, NULL, intEnable, false);
|
||||
ENET_UpdateRxDescriptorTail(wrapper->ethernetif->base, 0U,
|
||||
(uint32_t)ethernetif_get_rx_desc(wrapper->ethernetif, ENET_RXBD_NUM));
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of a received frame (if there is some).
|
||||
*/
|
||||
static status_t ethernetif_get_rx_frame_size(struct ethernetif *ethernetif,
|
||||
uint32_t *length)
|
||||
{
|
||||
uint8_t index = ethernetif->rxIdx;
|
||||
enet_rx_bd_struct_t *rxDesc;
|
||||
uint32_t rxControl;
|
||||
|
||||
/* Reset the length to zero. */
|
||||
*length = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rxDesc = ethernetif_get_rx_desc(ethernetif, index);
|
||||
rxControl = ENET_GetRxDescriptor(rxDesc);
|
||||
|
||||
if ((rxControl & ENET_RXDESCRIP_WR_OWN_MASK)
|
||||
|| (ethernetif->rxPbufs[index].ownedByLwip))
|
||||
{
|
||||
/*
|
||||
* Buffer descriptor is owned by DMA or lwIP.
|
||||
* We haven't received any complete frame yet.
|
||||
*/
|
||||
return kStatus_ENET_RxFrameEmpty;
|
||||
}
|
||||
|
||||
/* Application owns the buffer descriptor. */
|
||||
if (rxControl & ENET_RXDESCRIP_WR_LD_MASK)
|
||||
{
|
||||
/* It's last descriptor of a frame, get its status or length. */
|
||||
if (rxControl & ENET_RXDESCRIP_WR_ERRSUM_MASK)
|
||||
{
|
||||
return kStatus_ENET_RxFrameError;
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK;
|
||||
return kStatus_Success;
|
||||
}
|
||||
}
|
||||
|
||||
index = (index + 1U) % ENET_RXBD_NUM;
|
||||
} while (index != ethernetif->rxIdx);
|
||||
|
||||
/*
|
||||
* All descriptors have data but the end of the frame not detected.
|
||||
*/
|
||||
return kStatus_ENET_RxFrameError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops (releases) receive descriptors until the last one of a frame is reached
|
||||
* or drops entire descriptor ring when all descriptors have data but end
|
||||
* of the frame not detected among them.
|
||||
* Function can be called only after ethernetif_get_rx_frame_size() indicates
|
||||
* that there actually is a frame error or a received frame.
|
||||
*/
|
||||
static void ethernetif_drop_frame(struct ethernetif *ethernetif)
|
||||
{
|
||||
#if NO_SYS
|
||||
bool intEnable = false;
|
||||
#else
|
||||
bool intEnable = true;
|
||||
#endif /* NO_SYS */
|
||||
|
||||
enet_rx_bd_struct_t *rxDesc;
|
||||
uint8_t index = ethernetif->rxIdx;
|
||||
uint32_t rxControl;
|
||||
|
||||
do
|
||||
{
|
||||
rxDesc = ethernetif_get_rx_desc(ethernetif, ethernetif->rxIdx);
|
||||
ethernetif->rxIdx = (ethernetif->rxIdx + 1U) % ENET_RXBD_NUM;
|
||||
rxControl = ENET_GetRxDescriptor(rxDesc);
|
||||
|
||||
/* Update the receive buffer descriptor. */
|
||||
ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, intEnable, false);
|
||||
|
||||
/* Find the last buffer descriptor for the frame. */
|
||||
if (rxControl & ENET_RXDESCRIP_WR_LD_MASK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (ethernetif->rxIdx != index);
|
||||
|
||||
ENET_UpdateRxDescriptorTail(ethernetif->base, 0U,
|
||||
(uint32_t)ethernetif_get_rx_desc(ethernetif, ENET_RXBD_NUM));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a received frame - wraps its descriptor buffer(s) into a pbuf
|
||||
* or a pbuf chain, flag descriptors as owned by lwIP and returns the pbuf.
|
||||
* The descriptors are returned to DMA only after the returned pbuf is released.
|
||||
* Function can be called only after ethernetif_get_rx_frame_size() indicates
|
||||
* that there actually is a received frame.
|
||||
*/
|
||||
static struct pbuf *ethernetif_read_frame(struct ethernetif *ethernetif,
|
||||
uint32_t length)
|
||||
{
|
||||
rx_pbuf_wrapper_t *wrapper;
|
||||
enet_rx_bd_struct_t *rxDesc;
|
||||
uint32_t rxControl;
|
||||
uint32_t len = 0;
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf *q = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
wrapper = ðernetif->rxPbufs[ethernetif->rxIdx];
|
||||
wrapper->ownedByLwip = true;
|
||||
ethernetif->rxIdx = (ethernetif->rxIdx + 1U) % ENET_RXBD_NUM;
|
||||
|
||||
rxDesc = wrapper->rxDesc;
|
||||
rxControl = ENET_GetRxDescriptor(rxDesc);
|
||||
|
||||
len = (rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK);
|
||||
|
||||
/* Wrap the receive buffer in pbuf. */
|
||||
if (p == NULL)
|
||||
{
|
||||
p = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &wrapper->p,
|
||||
(void *)rxDesc->buff1Addr, len);
|
||||
LWIP_ASSERT("pbuf_alloced_custom() failed", p);
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
/* Add the padding header, force because it is a REF type buffer. */
|
||||
pbuf_header_force(p, ETH_PAD_SIZE);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
q = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &wrapper->p,
|
||||
(void *)rxDesc->buff1Addr, len);
|
||||
LWIP_ASSERT("pbuf_alloced_custom() failed", q);
|
||||
|
||||
pbuf_cat(p, q);
|
||||
}
|
||||
} while (((rxControl & ENET_RXDESCRIP_WR_LD_MASK) == 0U)
|
||||
&& (p->tot_len < length));
|
||||
|
||||
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
|
||||
if (((u8_t *)p->payload)[0] & 1)
|
||||
{
|
||||
/* broadcast or multicast packet */
|
||||
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast packet */
|
||||
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
|
||||
}
|
||||
|
||||
LINK_STATS_INC(link.recv);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read a frame from ENET and returns it wrapped in a pbuf
|
||||
* or returns NULL when no frame is received. Discards invalid frames.
|
||||
*/
|
||||
struct pbuf *ethernetif_linkinput(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
struct pbuf *p = NULL;
|
||||
uint32_t len;
|
||||
status_t status;
|
||||
|
||||
/* Obtain the size of the packet and put it into the "len" variable. */
|
||||
status = ethernetif_get_rx_frame_size(ethernetif, &len);
|
||||
|
||||
if (status == kStatus_Success)
|
||||
{
|
||||
p = ethernetif_read_frame(ethernetif, len);
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
/* Could not initialise wrapper pbuf(s) - drop the frame. */
|
||||
ethernetif_drop_frame(ethernetif);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG,
|
||||
("ethernetif_linkinput: Fail to allocate new memory space\n"));
|
||||
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
MIB2_STATS_NETIF_INC(netif, ifindiscards);
|
||||
}
|
||||
}
|
||||
else if (status == kStatus_ENET_RxFrameError)
|
||||
{
|
||||
/* Update the received buffer when error happened. */
|
||||
ethernetif_drop_frame(ethernetif);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: RxFrameError\n"));
|
||||
|
||||
LINK_STATS_INC(link.drop);
|
||||
MIB2_STATS_NETIF_INC(netif, ifindiscards);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of TX descriptors which could be used by lwIP/application
|
||||
* to put new TX data into.
|
||||
*
|
||||
* The max number of free descriptors is (ENET_TXBD_NUM - 1), that is when
|
||||
* ethernetif->txReleaseIdx == ethernetif->txIdx. Having the capacity decreased
|
||||
* by one allows to avoid locking: txReleaseIdx is advanced only from ISR
|
||||
* and txIdx from tcpip_thread/main loop. Should we use full capacity and have
|
||||
* some variable to indicate between the "all buffers are free" vs. "all buffers
|
||||
* are used" situation, it would be manipulated from two contexts hence locking
|
||||
* would be needed.
|
||||
*/
|
||||
static inline int ethernetif_avail_tx_descs(struct ethernetif *ethernetif)
|
||||
{
|
||||
return (ethernetif->txReleaseIdx + ENET_TXBD_NUM - 1 - ethernetif->txIdx)
|
||||
% ENET_TXBD_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to output a frame from ENET. The function avoids copying of
|
||||
* p's payload when possible. In such situation it increases p's reference count
|
||||
* and decreases it (and possibly releases p) after the payload is sent.
|
||||
*/
|
||||
err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct ethernetif *ethernetif = netif->state;
|
||||
struct pbuf *q;
|
||||
struct pbuf *pbuf_to_free = NULL;
|
||||
struct pbuf *p_copy;
|
||||
uint16_t clen;
|
||||
bool copy = false;
|
||||
const mem_range_t *non_dma_memory;
|
||||
uint8_t *dst;
|
||||
uint32_t cnt = 0;
|
||||
uint8_t first_idx;
|
||||
uint32_t tail_address;
|
||||
|
||||
LWIP_ASSERT("Output packet buffer empty", p);
|
||||
|
||||
if ((p->tot_len - ETH_PAD_SIZE) > ENET_FRAME_MAX_FRAMELEN)
|
||||
{
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
clen = pbuf_clen(p);
|
||||
|
||||
/* Check if relocation is needed */
|
||||
|
||||
if (clen > (ENET_TXBD_NUM - 1))
|
||||
{
|
||||
/* Pbuf chain is too long to be prepared for DMA at once. */
|
||||
copy = true;
|
||||
}
|
||||
|
||||
for (q = p; (q != NULL) && !copy; q = q->next)
|
||||
{
|
||||
/*
|
||||
* Check if payload is aligned is not desired: lwIP creates RAM pbufs
|
||||
* in a way that the data coming after the headers are aligned, but not
|
||||
* the beginning of the ethernet header. LPC ENET DMA will read from
|
||||
* the aligned address, which is ok, because there is additional space
|
||||
* before the headers to make up for alignment - so DMA will not read
|
||||
* from invalid address or unrelated data.
|
||||
*/
|
||||
|
||||
/* Check payload address is usable by ENET DMA */
|
||||
for (non_dma_memory = ethernetif->non_dma_memory;
|
||||
(non_dma_memory->start != 0U)
|
||||
|| (non_dma_memory->end != 0U); non_dma_memory++)
|
||||
{
|
||||
if ((q->payload >= (void *) non_dma_memory->start)
|
||||
&& (q->payload < (void *) non_dma_memory->end))
|
||||
{
|
||||
copy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (copy)
|
||||
{
|
||||
/* Pbuf needs to be copied. */
|
||||
|
||||
p_copy = pbuf_alloc(PBUF_RAW, (uint16_t) p->tot_len, PBUF_POOL);
|
||||
if (p_copy == NULL)
|
||||
{
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
dst = (uint8_t *) p_copy->payload;
|
||||
for (q = p; q != NULL; q = q->next)
|
||||
{
|
||||
LWIP_ASSERT("Copied bytes would exceed p->tot_len",
|
||||
(q->len + dst - (uint8_t *) p_copy->payload) <= p->tot_len);
|
||||
memcpy(dst, (uint8_t *)q->payload, q->len);
|
||||
dst += q->len;
|
||||
}
|
||||
LWIP_ASSERT("Copied bytes != p->tot_len",
|
||||
(dst - (uint8_t *) p_copy->payload) == p->tot_len);
|
||||
p_copy->len = p_copy->tot_len = p->tot_len;
|
||||
|
||||
p = p_copy;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Increase reference count so p is released only after it is sent.
|
||||
* For copied pbuf, ref is already 1 after pbuf_alloc().
|
||||
*/
|
||||
pbuf_ref(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until the sufficient number of descriptors are available,
|
||||
* as we have to start the transfer of the first buffer only
|
||||
* after all buffers in chain are prepared.
|
||||
*/
|
||||
while (ethernetif_avail_tx_descs(ethernetif) < clen)
|
||||
{
|
||||
#if !NO_SYS
|
||||
xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent,
|
||||
ethernetif->txFlag, pdTRUE, (BaseType_t) false,
|
||||
portMAX_DELAY);
|
||||
#endif /* !NO_SYS */
|
||||
cnt++;
|
||||
if (cnt >= ENET_TIMEOUT)
|
||||
{
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
/* Drop the padding. */
|
||||
pbuf_header(p, -ETH_PAD_SIZE);
|
||||
#endif
|
||||
|
||||
/* Initiate transfer. */
|
||||
|
||||
first_idx = ethernetif->txIdx;
|
||||
|
||||
for (q = p; q != NULL; q = q->next)
|
||||
{
|
||||
enet_desc_flag flag = kENET_MiddleFlag;
|
||||
pbuf_to_free = NULL;
|
||||
|
||||
if (q == p)
|
||||
{
|
||||
flag |= kENET_FirstFlagOnly;
|
||||
}
|
||||
|
||||
if (q->next == NULL)
|
||||
{
|
||||
flag |= kENET_LastFlagOnly;
|
||||
|
||||
/* On last TX interrupt, free pbuf chain. */
|
||||
pbuf_to_free = p;
|
||||
}
|
||||
|
||||
ethernetif_send_buffer(ethernetif, q->payload, q->len, pbuf_to_free,
|
||||
flag);
|
||||
}
|
||||
|
||||
/* All pbufs from chain are prepared, allow DMA to access the first one. */
|
||||
ethernetif_get_tx_desc(ethernetif, first_idx)->controlStat |=
|
||||
ENET_TXDESCRIP_RD_OWN_MASK;
|
||||
|
||||
/* Update the transmit tail address. */
|
||||
if (ethernetif->txIdx == 0U)
|
||||
{
|
||||
tail_address = (uint32_t)ethernetif_get_tx_desc(ethernetif,
|
||||
ENET_TXBD_NUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
tail_address = (uint32_t)ethernetif_get_tx_desc(ethernetif,
|
||||
ethernetif->txIdx);
|
||||
}
|
||||
ENET_UpdateTxDescriptorTail(ethernetif->base, 0, tail_address);
|
||||
|
||||
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
|
||||
if (((uint8_t *)p->payload)[0] & 1)
|
||||
{
|
||||
/* broadcast or multicast packet */
|
||||
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast packet */
|
||||
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
|
||||
}
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* first network interface. It calls the function ethernetif_init() to do the
|
||||
* actual setup of the hardware.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t ethernetif0_init(struct netif *netif)
|
||||
{
|
||||
static struct ethernetif ethernetif_0;
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rxBuffDescrip_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t txBuffDescrip_0[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
SDK_ALIGN(static rx_buffer_t rxDataBuff_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
|
||||
ethernetif_0.RxBuffDescrip = &(rxBuffDescrip_0[0]);
|
||||
ethernetif_0.TxBuffDescrip = &(txBuffDescrip_0[0]);
|
||||
ethernetif_0.RxDataBuff = &(rxDataBuff_0[0]);
|
||||
|
||||
return ethernetif_init(netif, ðernetif_0, 0U, (ethernetif_config_t *)netif->state);
|
||||
}
|
||||
|
||||
#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 1)
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* second network interface. It calls the function ethernetif_init() to do the
|
||||
* actual setup of the hardware.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t ethernetif1_init(struct netif *netif)
|
||||
{
|
||||
static struct ethernetif ethernetif_1;
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rxBuffDescrip_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t txBuffDescrip_1[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
SDK_ALIGN(static rx_buffer_t rxDataBuff_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT);
|
||||
|
||||
ethernetif_1.RxBuffDescrip = &(rxBuffDescrip_1[0]);
|
||||
ethernetif_1.TxBuffDescrip = &(txBuffDescrip_1[0]);
|
||||
ethernetif_1.RxDataBuff = &(rxDataBuff_1[0]);
|
||||
|
||||
return ethernetif_init(netif, ðernetif_1, 1U, (ethernetif_config_t *)netif->state);
|
||||
}
|
||||
#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
SRC_FILES := fsl_phy.c
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2018 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file fsl_phy.c
|
||||
* @brief phy drivers for ksz8081
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include "lwipopts.h"
|
||||
#include "fsl_phy.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/*! @brief Defines the timeout macro. */
|
||||
#define PHY_TIMEOUT_COUNT 100000
|
||||
|
||||
/*******************************************************************************
|
||||
* Prototypes
|
||||
******************************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Get the ENET instance from peripheral base address.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @return ENET instance.
|
||||
*/
|
||||
extern uint32_t ENET_GetInstance(ENET_Type *base);
|
||||
|
||||
/*******************************************************************************
|
||||
* Variables
|
||||
******************************************************************************/
|
||||
|
||||
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
||||
/*! @brief Pointers to enet clocks for each instance. */
|
||||
extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
|
||||
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
******************************************************************************/
|
||||
|
||||
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
|
||||
{
|
||||
uint32_t bssReg;
|
||||
uint32_t counter = PHY_TIMEOUT_COUNT;
|
||||
uint32_t idReg = 0;
|
||||
status_t result = kStatus_Success;
|
||||
uint32_t instance = ENET_GetInstance(base);
|
||||
uint32_t timeDelay;
|
||||
uint32_t ctlReg = 0;
|
||||
|
||||
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
||||
/* Set SMI first. */
|
||||
CLOCK_EnableClock(s_enetClock[instance]);
|
||||
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
||||
ENET_SetSMI(base, srcClock_Hz, false);
|
||||
|
||||
/* Initialization after PHY stars to work. */
|
||||
while ((idReg != PHY_CONTROL_ID1) && (counter != 0))
|
||||
{
|
||||
PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
|
||||
counter--;
|
||||
}
|
||||
|
||||
if (!counter)
|
||||
{
|
||||
return kStatus_Fail;
|
||||
}
|
||||
|
||||
/* Reset PHY. */
|
||||
counter = PHY_TIMEOUT_COUNT;
|
||||
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
#if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE)
|
||||
uint32_t data = 0;
|
||||
result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
|
||||
if (result != kStatus_Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REFCLK_SELECT_MASK));
|
||||
if (result != kStatus_Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
#endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
|
||||
|
||||
/* Set the negotiation. */
|
||||
result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
|
||||
(PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
|
||||
PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
result =
|
||||
PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
/* Check auto negotiation complete. */
|
||||
while (counter--)
|
||||
{
|
||||
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
|
||||
if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) && (ctlReg & PHY_LINK_READY_MASK))
|
||||
{
|
||||
/* Wait a moment for Phy status stable. */
|
||||
for (timeDelay = 0; timeDelay < PHY_TIMEOUT_COUNT; timeDelay++)
|
||||
{
|
||||
__ASM("nop");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!counter)
|
||||
{
|
||||
return kStatus_PHY_AutoNegotiateFail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
|
||||
{
|
||||
uint32_t counter;
|
||||
|
||||
/* Clear the SMI interrupt event. */
|
||||
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
|
||||
|
||||
/* Starts a SMI write command. */
|
||||
ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);
|
||||
|
||||
/* Wait for SMI complete. */
|
||||
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
|
||||
{
|
||||
if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for timeout. */
|
||||
if (!counter)
|
||||
{
|
||||
return kStatus_PHY_SMIVisitTimeout;
|
||||
}
|
||||
|
||||
/* Clear MII interrupt event. */
|
||||
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
|
||||
|
||||
return kStatus_Success;
|
||||
}
|
||||
|
||||
status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
|
||||
{
|
||||
assert(dataPtr);
|
||||
|
||||
uint32_t counter;
|
||||
|
||||
/* Clear the MII interrupt event. */
|
||||
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
|
||||
|
||||
/* Starts a SMI read command operation. */
|
||||
ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);
|
||||
|
||||
/* Wait for MII complete. */
|
||||
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
|
||||
{
|
||||
if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for timeout. */
|
||||
if (!counter)
|
||||
{
|
||||
return kStatus_PHY_SMIVisitTimeout;
|
||||
}
|
||||
|
||||
/* Get data from MII register. */
|
||||
*dataPtr = ENET_ReadSMIData(base);
|
||||
|
||||
/* Clear MII interrupt event. */
|
||||
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
|
||||
|
||||
return kStatus_Success;
|
||||
}
|
||||
|
||||
status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable)
|
||||
{
|
||||
status_t result;
|
||||
uint32_t data = 0;
|
||||
|
||||
/* Set the loop mode. */
|
||||
if (enable)
|
||||
{
|
||||
if (mode == kPHY_LocalLoop)
|
||||
{
|
||||
if (speed == kPHY_Speed100M)
|
||||
{
|
||||
data = PHY_BCTL_SPEED_100M_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
|
||||
}
|
||||
return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First read the current status in control register. */
|
||||
result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REMOTELOOP_MASK));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the loop mode. */
|
||||
if (mode == kPHY_LocalLoop)
|
||||
{
|
||||
/* First read the current status in control register. */
|
||||
result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
data &= ~PHY_BCTL_LOOP_MASK;
|
||||
return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data | PHY_BCTL_RESTART_AUTONEG_MASK));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First read the current status in control one register. */
|
||||
result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data & ~PHY_CTL2_REMOTELOOP_MASK));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
|
||||
{
|
||||
assert(status);
|
||||
|
||||
status_t result = kStatus_Success;
|
||||
uint32_t data;
|
||||
|
||||
/* Read the basic status register. */
|
||||
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
if (!(PHY_BSTATUS_LINKSTATUS_MASK & data))
|
||||
{
|
||||
/* link down. */
|
||||
*status = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* link up. */
|
||||
*status = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
|
||||
{
|
||||
assert(duplex);
|
||||
|
||||
status_t result = kStatus_Success;
|
||||
uint32_t data, ctlReg;
|
||||
|
||||
|
||||
/* Read the control two register. */
|
||||
result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
|
||||
if (result == kStatus_Success)
|
||||
{
|
||||
data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
|
||||
if ((PHY_CTL1_10FULLDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
|
||||
{
|
||||
/* Full duplex. */
|
||||
*duplex = kPHY_FullDuplex;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Half duplex. */
|
||||
*duplex = kPHY_HalfDuplex;
|
||||
}
|
||||
|
||||
data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
|
||||
if ((PHY_CTL1_100HALFDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
|
||||
{
|
||||
/* 100M speed. */
|
||||
*speed = kPHY_Speed100M;
|
||||
}
|
||||
else
|
||||
{ /* 10M speed. */
|
||||
*speed = kPHY_Speed10M;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2017 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file fsl_phy.h
|
||||
* @brief phy drivers for ksz8081
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#ifndef _FSL_PHY_H_
|
||||
#define _FSL_PHY_H_
|
||||
|
||||
#include "fsl_enet.h"
|
||||
|
||||
/*!
|
||||
* @addtogroup phy_driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/*! @brief PHY driver version */
|
||||
#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */
|
||||
|
||||
/*! @brief Defines the PHY registers. */
|
||||
#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */
|
||||
#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */
|
||||
#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */
|
||||
#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */
|
||||
#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */
|
||||
#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */
|
||||
#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */
|
||||
|
||||
#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1*/
|
||||
|
||||
/*! @brief Defines the mask flag in basic control register. */
|
||||
#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */
|
||||
#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */
|
||||
#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */
|
||||
#define PHY_BCTL_SPEED_MASK 0x2000U /*!< The PHY speed bit mask. */
|
||||
#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */
|
||||
#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */
|
||||
#define PHY_BCTL_SPEED_100M_MASK 0x2000U /*!< The PHY 100M speed mask. */
|
||||
|
||||
/*!@brief Defines the mask flag of operation mode in control two register*/
|
||||
#define PHY_CTL2_REMOTELOOP_MASK 0x0004U /*!< The PHY remote loopback mask. */
|
||||
#define PHY_CTL2_REFCLK_SELECT_MASK 0x0080U /*!< The PHY RMII reference clock select. */
|
||||
#define PHY_CTL1_10HALFDUPLEX_MASK 0x0001U /*!< The PHY 10M half duplex mask. */
|
||||
#define PHY_CTL1_100HALFDUPLEX_MASK 0x0002U /*!< The PHY 100M half duplex mask. */
|
||||
#define PHY_CTL1_10FULLDUPLEX_MASK 0x0005U /*!< The PHY 10M full duplex mask. */
|
||||
#define PHY_CTL1_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */
|
||||
#define PHY_CTL1_SPEEDUPLX_MASK 0x0007U /*!< The PHY speed and duplex mask. */
|
||||
#define PHY_CTL1_ENERGYDETECT_MASK 0x10U /*!< The PHY signal present on rx differential pair. */
|
||||
#define PHY_CTL1_LINKUP_MASK 0x100U /*!< The PHY link up. */
|
||||
#define PHY_LINK_READY_MASK (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK)
|
||||
|
||||
/*! @brief Defines the mask flag in basic status register. */
|
||||
#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */
|
||||
#define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */
|
||||
#define PHY_BSTATUS_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */
|
||||
|
||||
/*! @brief Defines the mask flag in PHY auto-negotiation advertise register. */
|
||||
#define PHY_100BaseT4_ABILITY_MASK 0x200U /*!< The PHY have the T4 ability. */
|
||||
#define PHY_100BASETX_FULLDUPLEX_MASK 0x100U /*!< The PHY has the 100M full duplex ability.*/
|
||||
#define PHY_100BASETX_HALFDUPLEX_MASK 0x080U /*!< The PHY has the 100M full duplex ability.*/
|
||||
#define PHY_10BASETX_FULLDUPLEX_MASK 0x040U /*!< The PHY has the 10M full duplex ability.*/
|
||||
#define PHY_10BASETX_HALFDUPLEX_MASK 0x020U /*!< The PHY has the 10M full duplex ability.*/
|
||||
|
||||
/*! @brief Defines the PHY status. */
|
||||
enum _phy_status
|
||||
{
|
||||
kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 1), /*!< ENET PHY SMI visit timeout. */
|
||||
kStatus_PHY_AutoNegotiateFail = MAKE_STATUS(kStatusGroup_PHY, 2) /*!< ENET PHY AutoNegotiate Fail. */
|
||||
};
|
||||
|
||||
/*! @brief Defines the PHY link speed. This is align with the speed for ENET MAC. */
|
||||
typedef enum _phy_speed
|
||||
{
|
||||
kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */
|
||||
kPHY_Speed100M /*!< ENET PHY 100M speed. */
|
||||
} phy_speed_t;
|
||||
|
||||
/*! @brief Defines the PHY link duplex. */
|
||||
typedef enum _phy_duplex
|
||||
{
|
||||
kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */
|
||||
kPHY_FullDuplex /*!< ENET PHY full duplex. */
|
||||
} phy_duplex_t;
|
||||
|
||||
/*! @brief Defines the PHY loopback mode. */
|
||||
typedef enum _phy_loop
|
||||
{
|
||||
kPHY_LocalLoop = 0U, /*!< ENET PHY local loopback. */
|
||||
kPHY_RemoteLoop /*!< ENET PHY remote loopback. */
|
||||
} phy_loop_t;
|
||||
|
||||
/*******************************************************************************
|
||||
* API
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @name PHY Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Initializes PHY.
|
||||
*
|
||||
* This function initialize the SMI interface and initialize PHY.
|
||||
* The SMI is the MII management interface between PHY and MAC, which should be
|
||||
* firstly initialized before any other operation for PHY. The PHY initialize with auto-negotiation.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @param phyAddr The PHY address.
|
||||
* @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI.
|
||||
* @retval kStatus_Success PHY initialize success
|
||||
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
|
||||
* @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail
|
||||
*/
|
||||
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz);
|
||||
|
||||
/*!
|
||||
* @brief PHY Write function. This function write data over the SMI to
|
||||
* the specified PHY register. This function is called by all PHY interfaces.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @param phyAddr The PHY address.
|
||||
* @param phyReg The PHY register.
|
||||
* @param data The data written to the PHY register.
|
||||
* @retval kStatus_Success PHY write success
|
||||
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
|
||||
*/
|
||||
status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data);
|
||||
|
||||
/*!
|
||||
* @brief PHY Read function. This interface read data over the SMI from the
|
||||
* specified PHY register. This function is called by all PHY interfaces.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @param phyAddr The PHY address.
|
||||
* @param phyReg The PHY register.
|
||||
* @param dataPtr The address to store the data read from the PHY register.
|
||||
* @retval kStatus_Success PHY read success
|
||||
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
|
||||
*/
|
||||
status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr);
|
||||
|
||||
/*!
|
||||
* @brief Enables/disables PHY loopback.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @param phyAddr The PHY address.
|
||||
* @param mode The loopback mode to be enabled, please see "phy_loop_t".
|
||||
* the two loopback mode should not be both set. when one loopback mode is set
|
||||
* the other one should be disabled.
|
||||
* @param speed PHY speed for loopback mode.
|
||||
* @param enable True to enable, false to disable.
|
||||
* @retval kStatus_Success PHY loopback success
|
||||
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
|
||||
*/
|
||||
status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable);
|
||||
|
||||
/*!
|
||||
* @brief Gets the PHY link status.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @param phyAddr The PHY address.
|
||||
* @param status The link up or down status of the PHY.
|
||||
* - true the link is up.
|
||||
* - false the link is down.
|
||||
* @retval kStatus_Success PHY get link status success
|
||||
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
|
||||
*/
|
||||
status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status);
|
||||
|
||||
/*!
|
||||
* @brief Gets the PHY link speed and duplex.
|
||||
*
|
||||
* @param base ENET peripheral base address.
|
||||
* @param phyAddr The PHY address.
|
||||
* @param speed The address of PHY link speed.
|
||||
* @param duplex The link duplex of PHY.
|
||||
* @retval kStatus_Success PHY get link speed and duplex success
|
||||
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
|
||||
*/
|
||||
status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex);
|
||||
|
||||
/* @} */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! @}*/
|
||||
|
||||
#endif /* _FSL_PHY_H_ */
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2021 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_ethernet.h
|
||||
* @brief Adapted network software protocol stack and hardware operation functions
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-12-7
|
||||
*/
|
||||
|
||||
#ifndef __CONNECT_ETHERNET_H_
|
||||
#define __CONNECT_ETHERNET_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef sourceClock
|
||||
#define sourceClock CLOCK_GetFreq(kCLOCK_CoreSysClk)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2016, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file enet_ethernetif.h
|
||||
* @brief ethernet drivers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ENET_ETHERNETIF_H
|
||||
#define ENET_ETHERNETIF_H
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "fsl_enet.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
#ifndef ENET_RXBD_NUM
|
||||
#define ENET_RXBD_NUM (5)
|
||||
#endif
|
||||
#ifndef ENET_TXBD_NUM
|
||||
#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
|
||||
#define ENET_TXBD_NUM (5)
|
||||
#else
|
||||
#define ENET_TXBD_NUM (3)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef ENET_RXBUFF_SIZE
|
||||
#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
|
||||
#define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN + ETH_PAD_SIZE)
|
||||
#else
|
||||
#define ENET_RXBUFF_SIZE ENET_FRAME_MAX_FRAMELEN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ENET_TXBUFF_SIZE
|
||||
#define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
|
||||
#endif
|
||||
|
||||
#define ENET_TIMEOUT (0xFFFU)
|
||||
|
||||
/* ENET IRQ priority. Used in FreeRTOS. */
|
||||
/* Interrupt priorities. */
|
||||
#ifdef __CA7_REV
|
||||
#ifndef ENET_PRIORITY
|
||||
#define ENET_PRIORITY (21U)
|
||||
#endif
|
||||
#ifndef ENET_1588_PRIORITY
|
||||
#define ENET_1588_PRIORITY (20U)
|
||||
#endif
|
||||
#else
|
||||
#ifndef ENET_PRIORITY
|
||||
#define ENET_PRIORITY (15U)//(6U)
|
||||
#endif
|
||||
#ifndef ENET_1588_PRIORITY
|
||||
#define ENET_1588_PRIORITY (5U)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Defines Ethernet Autonegotiation Timeout during initialization.
|
||||
* Set it to 0 to disable the waiting. */
|
||||
#ifndef ENET_ATONEGOTIATION_TIMEOUT
|
||||
#define ENET_ATONEGOTIATION_TIMEOUT (0xFFFU)
|
||||
#endif
|
||||
|
||||
/* Define those to better describe your network interface. */
|
||||
#define IFNAME0 'e'
|
||||
#define IFNAME1 'n'
|
||||
|
||||
#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
|
||||
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) \
|
||||
&& ((!defined(FSL_SDK_DISBLE_L2CACHE_PRESENT)) || (FSL_SDK_DISBLE_L2CACHE_PRESENT == 0))
|
||||
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
|
||||
#define FSL_CACHE_LINESIZE_MAX MAX(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE, FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
|
||||
#define FSL_ENET_BUFF_ALIGNMENT MAX(ENET_BUFF_ALIGNMENT, FSL_CACHE_LINESIZE_MAX)
|
||||
#else
|
||||
#define FSL_ENET_BUFF_ALIGNMENT MAX(ENET_BUFF_ALIGNMENT, FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
|
||||
#endif
|
||||
#elif defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
|
||||
#define FSL_ENET_BUFF_ALIGNMENT MAX(ENET_BUFF_ALIGNMENT, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
|
||||
#else
|
||||
#define FSL_ENET_BUFF_ALIGNMENT ENET_BUFF_ALIGNMENT
|
||||
#endif
|
||||
#else
|
||||
#define FSL_ENET_BUFF_ALIGNMENT ENET_BUFF_ALIGNMENT
|
||||
#endif
|
||||
|
||||
#define ENET_RING_NUM 1U
|
||||
|
||||
typedef uint8_t rx_buffer_t[SDK_SIZEALIGN(ENET_RXBUFF_SIZE, FSL_ENET_BUFF_ALIGNMENT)];
|
||||
typedef uint8_t tx_buffer_t[SDK_SIZEALIGN(ENET_TXBUFF_SIZE, FSL_ENET_BUFF_ALIGNMENT)];
|
||||
|
||||
#if (defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0))
|
||||
typedef struct mem_range
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
} mem_range_t;
|
||||
#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */
|
||||
|
||||
/**
|
||||
* Helper struct to hold data for configuration of ethernet interface.
|
||||
*/
|
||||
typedef struct ethernetif_config
|
||||
{
|
||||
uint32_t phyAddress;
|
||||
clock_name_t clockName;
|
||||
uint8_t macAddress[NETIF_MAX_HWADDR_LEN];
|
||||
#if (defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0))
|
||||
const mem_range_t *non_dma_memory;
|
||||
#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */
|
||||
} ethernetif_config_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* This function should be passed as a parameter to netif_add()
|
||||
* if you initialize the first ENET interface.
|
||||
*/
|
||||
err_t ethernetif0_init(struct netif *netif);
|
||||
|
||||
#if (defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 1)) \
|
||||
|| (defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 1))
|
||||
/**
|
||||
* This function should be passed as a parameter to netif_add()
|
||||
* if you initialize the second ENET interface.
|
||||
*/
|
||||
err_t ethernetif1_init(struct netif *netif);
|
||||
#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */
|
||||
|
||||
/**
|
||||
* This function should be called when a packet is ready to be read
|
||||
* from the interface.
|
||||
* It is used by bare-metal applications.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
*/
|
||||
void ethernetif_input( struct netif *netif);
|
||||
|
||||
void ETH_BSP_Config(void);
|
||||
|
||||
int32 lwip_obtain_semaphore(struct netif *netif);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ENET_ETHERNETIF_H */
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file enet_ethernetif_priv.h
|
||||
* @brief ethernet drivers
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ENET_ETHERNETIF_PRIV_H
|
||||
#define ENET_ETHERNETIF_PRIV_H
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
struct ethernetif;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
err_t ethernetif_init(struct netif *netif, struct ethernetif *ethernetif,
|
||||
const uint8_t enetIdx,
|
||||
const ethernetif_config_t *ethernetifConfig);
|
||||
|
||||
void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif,
|
||||
const ethernetif_config_t *ethernetifConfig);
|
||||
|
||||
void ethernetif_phy_init(struct ethernetif *ethernetif,
|
||||
const ethernetif_config_t *ethernetifConfig,
|
||||
enet_config_t *config);
|
||||
|
||||
ENET_Type **ethernetif_enet_ptr(struct ethernetif *ethernetif);
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IGMP
|
||||
err_t ethernetif_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group,
|
||||
enum netif_mac_filter_action action);
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group,
|
||||
enum netif_mac_filter_action action);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Should allocate a pbuf and transfer the bytes of the incoming
|
||||
* packet from the interface into the pbuf.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return a pbuf filled with the received packet (including MAC header)
|
||||
* NULL on memory error
|
||||
*/
|
||||
struct pbuf *ethernetif_linkinput(struct netif *netif);
|
||||
|
||||
/**
|
||||
* This function should do the actual transmission of the packet. The packet is
|
||||
* contained in the pbuf that is passed to the function. This pbuf
|
||||
* might be chained.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
||||
* @return ERR_OK if the packet could be sent
|
||||
* an err_t value if the packet couldn't be sent
|
||||
*
|
||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
||||
* strange results. You might consider waiting for space in the DMA queue
|
||||
* to become available since the stack doesn't retry to send a packet
|
||||
* dropped because of memory failure (except for the TCP timers).
|
||||
*/
|
||||
err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ENET_ETHERNETIF_PRIV_H */
|
|
@ -0,0 +1,830 @@
|
|||
/*
|
||||
* Copyright 2017-2018 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef _FSL_SEMC_H_
|
||||
#define _FSL_SEMC_H_
|
||||
|
||||
#include "fsl_common.h"
|
||||
|
||||
/*!
|
||||
* @addtogroup semc
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/*! @name Driver version */
|
||||
/*@{*/
|
||||
/*! @brief SEMC driver version 2.0.4. */
|
||||
#define FSL_SEMC_DRIVER_VERSION (MAKE_VERSION(2, 0, 4))
|
||||
/*@}*/
|
||||
|
||||
/*! @brief SEMC status. */
|
||||
enum _semc_status
|
||||
{
|
||||
kStatus_SEMC_InvalidDeviceType = MAKE_STATUS(kStatusGroup_SEMC, 0),
|
||||
kStatus_SEMC_IpCommandExecutionError = MAKE_STATUS(kStatusGroup_SEMC, 1),
|
||||
kStatus_SEMC_AxiCommandExecutionError = MAKE_STATUS(kStatusGroup_SEMC, 2),
|
||||
kStatus_SEMC_InvalidMemorySize = MAKE_STATUS(kStatusGroup_SEMC, 3),
|
||||
kStatus_SEMC_InvalidIpcmdDataSize = MAKE_STATUS(kStatusGroup_SEMC, 4),
|
||||
kStatus_SEMC_InvalidAddressPortWidth = MAKE_STATUS(kStatusGroup_SEMC, 5),
|
||||
kStatus_SEMC_InvalidDataPortWidth = MAKE_STATUS(kStatusGroup_SEMC, 6),
|
||||
kStatus_SEMC_InvalidSwPinmuxSelection = MAKE_STATUS(kStatusGroup_SEMC, 7),
|
||||
kStatus_SEMC_InvalidBurstLength = MAKE_STATUS(kStatusGroup_SEMC, 8),
|
||||
kStatus_SEMC_InvalidColumnAddressBitWidth = MAKE_STATUS(kStatusGroup_SEMC, 9),
|
||||
kStatus_SEMC_InvalidBaseAddress = MAKE_STATUS(kStatusGroup_SEMC, 10),
|
||||
kStatus_SEMC_InvalidTimerSetting = MAKE_STATUS(kStatusGroup_SEMC, 11),
|
||||
};
|
||||
|
||||
/*! @brief SEMC memory device type. */
|
||||
typedef enum _semc_mem_type
|
||||
{
|
||||
kSEMC_MemType_SDRAM = 0, /*!< SDRAM */
|
||||
kSEMC_MemType_SRAM, /*!< SRAM */
|
||||
kSEMC_MemType_NOR, /*!< NOR */
|
||||
kSEMC_MemType_NAND, /*!< NAND */
|
||||
kSEMC_MemType_8080 /*!< 8080. */
|
||||
} semc_mem_type_t;
|
||||
|
||||
/*! @brief SEMC WAIT/RDY polarity. */
|
||||
typedef enum _semc_waitready_polarity
|
||||
{
|
||||
kSEMC_LowActive = 0, /*!< Low active. */
|
||||
kSEMC_HighActive, /*!< High active. */
|
||||
} semc_waitready_polarity_t;
|
||||
|
||||
/*! @brief SEMC SDRAM Chip selection . */
|
||||
typedef enum _semc_sdram_cs
|
||||
{
|
||||
kSEMC_SDRAM_CS0 = 0, /*!< SEMC SDRAM CS0. */
|
||||
kSEMC_SDRAM_CS1, /*!< SEMC SDRAM CS1. */
|
||||
kSEMC_SDRAM_CS2, /*!< SEMC SDRAM CS2. */
|
||||
kSEMC_SDRAM_CS3 /*!< SEMC SDRAM CS3. */
|
||||
} semc_sdram_cs_t;
|
||||
|
||||
/*! @brief SEMC NAND device type. */
|
||||
typedef enum _semc_nand_access_type
|
||||
{
|
||||
kSEMC_NAND_ACCESS_BY_AXI = 0,
|
||||
kSEMC_NAND_ACCESS_BY_IPCMD,
|
||||
} semc_nand_access_type_t;
|
||||
|
||||
/*! @brief SEMC interrupts . */
|
||||
typedef enum _semc_interrupt_enable
|
||||
{
|
||||
kSEMC_IPCmdDoneInterrupt = SEMC_INTEN_IPCMDDONEEN_MASK, /*!< Ip command done interrupt. */
|
||||
kSEMC_IPCmdErrInterrupt = SEMC_INTEN_IPCMDERREN_MASK, /*!< Ip command error interrupt. */
|
||||
kSEMC_AXICmdErrInterrupt = SEMC_INTEN_AXICMDERREN_MASK, /*!< AXI command error interrupt. */
|
||||
kSEMC_AXIBusErrInterrupt = SEMC_INTEN_AXIBUSERREN_MASK /*!< AXI bus error interrupt. */
|
||||
} semc_interrupt_enable_t;
|
||||
|
||||
/*! @brief SEMC IP command data size in bytes. */
|
||||
typedef enum _semc_ipcmd_datasize
|
||||
{
|
||||
kSEMC_IPcmdDataSize_1bytes = 1, /*!< The IP command data size 1 byte. */
|
||||
kSEMC_IPcmdDataSize_2bytes, /*!< The IP command data size 2 byte. */
|
||||
kSEMC_IPcmdDataSize_3bytes, /*!< The IP command data size 3 byte. */
|
||||
kSEMC_IPcmdDataSize_4bytes /*!< The IP command data size 4 byte. */
|
||||
} semc_ipcmd_datasize_t;
|
||||
|
||||
/*! @brief SEMC auto-refresh timing. */
|
||||
typedef enum _semc_refresh_time
|
||||
{
|
||||
kSEMC_RefreshThreeClocks = 0x0U, /*!< The refresh timing with three bus clocks. */
|
||||
kSEMC_RefreshSixClocks, /*!< The refresh timing with six bus clocks. */
|
||||
kSEMC_RefreshNineClocks /*!< The refresh timing with nine bus clocks. */
|
||||
} semc_refresh_time_t;
|
||||
|
||||
/*! @brief CAS latency */
|
||||
typedef enum _semc_caslatency
|
||||
{
|
||||
kSEMC_LatencyOne = 1, /*!< Latency 1. */
|
||||
kSEMC_LatencyTwo, /*!< Latency 2. */
|
||||
kSEMC_LatencyThree, /*!< Latency 3. */
|
||||
} semc_caslatency_t;
|
||||
|
||||
/*! @brief SEMC sdram column address bit number. */
|
||||
typedef enum _semc_sdram_column_bit_num
|
||||
{
|
||||
kSEMC_SdramColunm_12bit = 0x0U, /*!< 12 bit. */
|
||||
kSEMC_SdramColunm_11bit, /*!< 11 bit. */
|
||||
kSEMC_SdramColunm_10bit, /*!< 10 bit. */
|
||||
kSEMC_SdramColunm_9bit, /*!< 9 bit. */
|
||||
} semc_sdram_column_bit_num_t;
|
||||
|
||||
/*! @brief SEMC sdram burst length. */
|
||||
typedef enum _semc_sdram_burst_len
|
||||
{
|
||||
kSEMC_Sdram_BurstLen1 = 0, /*!< Burst length 1*/
|
||||
kSEMC_Sdram_BurstLen2, /*!< Burst length 2*/
|
||||
kSEMC_Sdram_BurstLen4, /*!< Burst length 4*/
|
||||
kSEMC_Sdram_BurstLen8 /*!< Burst length 8*/
|
||||
} sem_sdram_burst_len_t;
|
||||
|
||||
/*! @brief SEMC nand column address bit number. */
|
||||
typedef enum _semc_nand_column_bit_num
|
||||
{
|
||||
kSEMC_NandColum_16bit = 0x0U, /*!< 16 bit. */
|
||||
kSEMC_NandColum_15bit, /*!< 15 bit. */
|
||||
kSEMC_NandColum_14bit, /*!< 14 bit. */
|
||||
kSEMC_NandColum_13bit, /*!< 13 bit. */
|
||||
kSEMC_NandColum_12bit, /*!< 12 bit. */
|
||||
kSEMC_NandColum_11bit, /*!< 11 bit. */
|
||||
kSEMC_NandColum_10bit, /*!< 10 bit. */
|
||||
kSEMC_NandColum_9bit, /*!< 9 bit. */
|
||||
} semc_nand_column_bit_num_t;
|
||||
|
||||
/*! @brief SEMC nand burst length. */
|
||||
typedef enum _semc_nand_burst_len
|
||||
{
|
||||
kSEMC_Nand_BurstLen1 = 0, /*!< Burst length 1*/
|
||||
kSEMC_Nand_BurstLen2, /*!< Burst length 2*/
|
||||
kSEMC_Nand_BurstLen4, /*!< Burst length 4*/
|
||||
kSEMC_Nand_BurstLen8, /*!< Burst length 8*/
|
||||
kSEMC_Nand_BurstLen16, /*!< Burst length 16*/
|
||||
kSEMC_Nand_BurstLen32, /*!< Burst length 32*/
|
||||
kSEMC_Nand_BurstLen64 /*!< Burst length 64*/
|
||||
} sem_nand_burst_len_t;
|
||||
|
||||
/*! @brief SEMC nor/sram column address bit number. */
|
||||
typedef enum _semc_norsram_column_bit_num
|
||||
{
|
||||
kSEMC_NorColum_12bit = 0x0U, /*!< 12 bit. */
|
||||
kSEMC_NorColum_11bit, /*!< 11 bit. */
|
||||
kSEMC_NorColum_10bit, /*!< 10 bit. */
|
||||
kSEMC_NorColum_9bit, /*!< 9 bit. */
|
||||
kSEMC_NorColum_8bit, /*!< 8 bit. */
|
||||
kSEMC_NorColum_7bit, /*!< 7 bit. */
|
||||
kSEMC_NorColum_6bit, /*!< 6 bit. */
|
||||
kSEMC_NorColum_5bit, /*!< 5 bit. */
|
||||
kSEMC_NorColum_4bit, /*!< 4 bit. */
|
||||
kSEMC_NorColum_3bit, /*!< 3 bit. */
|
||||
kSEMC_NorColum_2bit /*!< 2 bit. */
|
||||
} semc_norsram_column_bit_num_t;
|
||||
|
||||
/*! @brief SEMC nor/sram burst length. */
|
||||
typedef enum _semc_norsram_burst_len
|
||||
{
|
||||
kSEMC_Nor_BurstLen1 = 0, /*!< Burst length 1*/
|
||||
kSEMC_Nor_BurstLen2, /*!< Burst length 2*/
|
||||
kSEMC_Nor_BurstLen4, /*!< Burst length 4*/
|
||||
kSEMC_Nor_BurstLen8, /*!< Burst length 8*/
|
||||
kSEMC_Nor_BurstLen16, /*!< Burst length 16*/
|
||||
kSEMC_Nor_BurstLen32, /*!< Burst length 32*/
|
||||
kSEMC_Nor_BurstLen64 /*!< Burst length 64*/
|
||||
} sem_norsram_burst_len_t;
|
||||
|
||||
/*! @brief SEMC dbi column address bit number. */
|
||||
typedef enum _semc_dbi_column_bit_num
|
||||
{
|
||||
kSEMC_Dbi_Colum_12bit = 0x0U, /*!< 12 bit. */
|
||||
kSEMC_Dbi_Colum_11bit, /*!< 11 bit. */
|
||||
kSEMC_Dbi_Colum_10bit, /*!< 10 bit. */
|
||||
kSEMC_Dbi_Colum_9bit, /*!< 9 bit. */
|
||||
kSEMC_Dbi_Colum_8bit, /*!< 8 bit. */
|
||||
kSEMC_Dbi_Colum_7bit, /*!< 7 bit. */
|
||||
kSEMC_Dbi_Colum_6bit, /*!< 6 bit. */
|
||||
kSEMC_Dbi_Colum_5bit, /*!< 5 bit. */
|
||||
kSEMC_Dbi_Colum_4bit, /*!< 4 bit. */
|
||||
kSEMC_Dbi_Colum_3bit, /*!< 3 bit. */
|
||||
kSEMC_Dbi_Colum_2bit /*!< 2 bit. */
|
||||
} semc_dbi_column_bit_num_t;
|
||||
|
||||
/*! @brief SEMC dbi burst length. */
|
||||
typedef enum _semc_dbi_burst_len
|
||||
{
|
||||
kSEMC_Dbi_BurstLen1 = 0, /*!< Burst length 1*/
|
||||
kSEMC_Dbi_BurstLen2, /*!< Burst length 2*/
|
||||
kSEMC_Dbi_Dbi_BurstLen4, /*!< Burst length 4*/
|
||||
kSEMC_Dbi_BurstLen8, /*!< Burst length 8*/
|
||||
kSEMC_Dbi_BurstLen16, /*!< Burst length 16*/
|
||||
kSEMC_Dbi_BurstLen32, /*!< Burst length 32*/
|
||||
kSEMC_Dbi_BurstLen64 /*!< Burst length 64*/
|
||||
} sem_dbi_burst_len_t;
|
||||
|
||||
/*! @brief SEMC IOMUXC. */
|
||||
typedef enum _semc_iomux_pin
|
||||
{
|
||||
kSEMC_MUXA8 = SEMC_IOCR_MUX_A8_SHIFT, /*!< MUX A8 pin. */
|
||||
kSEMC_MUXCSX0 = SEMC_IOCR_MUX_CSX0_SHIFT, /*!< MUX CSX0 pin */
|
||||
kSEMC_MUXCSX1 = SEMC_IOCR_MUX_CSX1_SHIFT, /*!< MUX CSX1 Pin.*/
|
||||
kSEMC_MUXCSX2 = SEMC_IOCR_MUX_CSX2_SHIFT, /*!< MUX CSX2 Pin. */
|
||||
kSEMC_MUXCSX3 = SEMC_IOCR_MUX_CSX3_SHIFT, /*!< MUX CSX3 Pin. */
|
||||
kSEMC_MUXRDY = SEMC_IOCR_MUX_RDY_SHIFT /*!< MUX RDY pin. */
|
||||
} semc_iomux_pin;
|
||||
|
||||
/*! @brief SEMC NOR/PSRAM Address bit 27 A27. */
|
||||
typedef enum _semc_iomux_nora27_pin
|
||||
{
|
||||
kSEMC_MORA27_NONE = 0, /*!< No NOR/SRAM A27 pin. */
|
||||
kSEMC_NORA27_MUXCSX3 = SEMC_IOCR_MUX_CSX3_SHIFT, /*!< MUX CSX3 Pin. */
|
||||
kSEMC_NORA27_MUXRDY = SEMC_IOCR_MUX_RDY_SHIFT /*!< MUX RDY pin. */
|
||||
} semc_iomux_nora27_pin;
|
||||
|
||||
/*! @brief SEMC port size. */
|
||||
typedef enum _semc_port_size
|
||||
{
|
||||
kSEMC_PortSize8Bit = 0, /*!< 8-Bit port size. */
|
||||
kSEMC_PortSize16Bit /*!< 16-Bit port size. */
|
||||
} smec_port_size_t;
|
||||
|
||||
/*! @brief SEMC address mode. */
|
||||
typedef enum _semc_addr_mode
|
||||
{
|
||||
kSEMC_AddrDataMux = 0, /*!< SEMC address/data mux mode. */
|
||||
kSEMC_AdvAddrdataMux, /*!< Advanced address/data mux mode. */
|
||||
kSEMC_AddrDataNonMux /*!< Address/data non-mux mode. */
|
||||
} semc_addr_mode_t;
|
||||
|
||||
/*! @brief SEMC DQS read strobe mode. */
|
||||
typedef enum _semc_dqs_mode
|
||||
{
|
||||
kSEMC_Loopbackinternal = 0, /*!< Dummy read strobe loopbacked internally. */
|
||||
kSEMC_Loopbackdqspad, /*!< Dummy read strobe loopbacked from DQS pad. */
|
||||
} semc_dqs_mode_t;
|
||||
|
||||
/*! @brief SEMC ADV signal active polarity. */
|
||||
typedef enum _semc_adv_polarity
|
||||
{
|
||||
kSEMC_AdvActiveLow = 0, /*!< Adv active low. */
|
||||
kSEMC_AdvActivehigh, /*!< Adv active low. */
|
||||
} semc_adv_polarity_t;
|
||||
|
||||
/*! @brief SEMC RDY signal active polarity. */
|
||||
typedef enum _semc_rdy_polarity
|
||||
{
|
||||
kSEMC_RdyActiveLow = 0, /*!< Adv active low. */
|
||||
kSEMC_RdyActivehigh, /*!< Adv active low. */
|
||||
} semc_rdy_polarity_t;
|
||||
|
||||
/*! @brief SEMC IP command for NAND: address mode. */
|
||||
typedef enum _semc_ipcmd_nand_addrmode
|
||||
{
|
||||
kSEMC_NANDAM_ColumnRow = 0x0U, /*!< Address mode: column and row address(5Byte-CA0/CA1/RA0/RA1/RA2). */
|
||||
kSEMC_NANDAM_ColumnCA0, /*!< Address mode: column address only(1 Byte-CA0). */
|
||||
kSEMC_NANDAM_ColumnCA0CA1, /*!< Address mode: column address only(2 Byte-CA0/CA1). */
|
||||
kSEMC_NANDAM_RawRA0, /*!< Address mode: row address only(1 Byte-RA0). */
|
||||
kSEMC_NANDAM_RawRA0RA1, /*!< Address mode: row address only(2 Byte-RA0/RA1). */
|
||||
kSEMC_NANDAM_RawRA0RA1RA2 /*!< Address mode: row address only(3 Byte-RA0). */
|
||||
} semc_ipcmd_nand_addrmode_t;
|
||||
|
||||
/*! @brief SEMC IP command for NAND: command mode. */
|
||||
typedef enum _semc_ipcmd_nand_cmdmode
|
||||
{
|
||||
kSEMC_NANDCM_Command = 0x2U, /*!< command. */
|
||||
kSEMC_NANDCM_CommandHold, /*!< Command hold. */
|
||||
kSEMC_NANDCM_CommandAddress, /*!< Command address. */
|
||||
kSEMC_NANDCM_CommandAddressHold, /*!< Command address hold. */
|
||||
kSEMC_NANDCM_CommandAddressRead, /*!< Command address read. */
|
||||
kSEMC_NANDCM_CommandAddressWrite, /*!< Command address write. */
|
||||
kSEMC_NANDCM_CommandRead, /*!< Command read. */
|
||||
kSEMC_NANDCM_CommandWrite, /*!< Command write. */
|
||||
kSEMC_NANDCM_Read, /*!< Read. */
|
||||
kSEMC_NANDCM_Write /*!< Write. */
|
||||
} semc_ipcmd_nand_cmdmode_t;
|
||||
|
||||
/*! @brief SEMC NAND address option. */
|
||||
typedef enum _semc_nand_address_option
|
||||
{
|
||||
kSEMC_NandAddrOption_5byte_CA2RA3 = 0U, /*!< CA0+CA1+RA0+RA1+RA2 */
|
||||
kSEMC_NandAddrOption_4byte_CA2RA2 = 2U, /*!< CA0+CA1+RA0+RA1 */
|
||||
kSEMC_NandAddrOption_3byte_CA2RA1 = 4U, /*!< CA0+CA1+RA0 */
|
||||
kSEMC_NandAddrOption_4byte_CA1RA3 = 1U, /*!< CA0+RA0+RA1+RA2 */
|
||||
kSEMC_NandAddrOption_3byte_CA1RA2 = 3U, /*!< CA0+RA0+RA1 */
|
||||
kSEMC_NandAddrOption_2byte_CA1RA1 = 7U, /*!< CA0+RA0 */
|
||||
} semc_nand_address_option_t;
|
||||
|
||||
/*! @brief SEMC IP command for NOR. */
|
||||
typedef enum _semc_ipcmd_nor_dbi
|
||||
{
|
||||
kSEMC_NORDBICM_Read = 0x2U, /*!< NOR read. */
|
||||
kSEMC_NORDBICM_Write /*!< NOR write. */
|
||||
} semc_ipcmd_nor_dbi_t;
|
||||
|
||||
/*! @brief SEMC IP command for SRAM. */
|
||||
typedef enum _semc_ipcmd_sram
|
||||
{
|
||||
kSEMC_SRAMCM_ArrayRead = 0x2U, /*!< SRAM memory array read. */
|
||||
kSEMC_SRAMCM_ArrayWrite, /*!< SRAM memory array write. */
|
||||
kSEMC_SRAMCM_RegRead, /*!< SRAM memory register read. */
|
||||
kSEMC_SRAMCM_RegWrite /*!< SRAM memory register write. */
|
||||
} semc_ipcmd_sram_t;
|
||||
|
||||
/*! @brief SEMC IP command for SDARM. */
|
||||
typedef enum _semc_ipcmd_sdram
|
||||
{
|
||||
kSEMC_SDRAMCM_Read = 0x8U, /*!< SDRAM memory read. */
|
||||
kSEMC_SDRAMCM_Write, /*!< SDRAM memory write. */
|
||||
kSEMC_SDRAMCM_Modeset, /*!< SDRAM MODE SET. */
|
||||
kSEMC_SDRAMCM_Active, /*!< SDRAM active. */
|
||||
kSEMC_SDRAMCM_AutoRefresh, /*!< SDRAM auto-refresh. */
|
||||
kSEMC_SDRAMCM_SelfRefresh, /*!< SDRAM self-refresh. */
|
||||
kSEMC_SDRAMCM_Precharge, /*!< SDRAM precharge. */
|
||||
kSEMC_SDRAMCM_Prechargeall /*!< SDRAM precharge all. */
|
||||
} semc_ipcmd_sdram_t;
|
||||
|
||||
/*! @brief SEMC SDRAM configuration structure.
|
||||
*
|
||||
* 1. The memory size in the configuration is in the unit of KB. So memsize_kbytes
|
||||
* should be set as 2^2, 2^3, 2^4 .etc which is base 2KB exponential function.
|
||||
* Take refer to BR0~BR3 register in RM for details.
|
||||
* 2. The prescalePeriod_N16Cycle is in unit of 16 clock cycle. It is a exception for prescaleTimer_n16cycle = 0,
|
||||
* it means the prescaler timer period is 256 * 16 clock cycles. For precalerIf precalerTimer_n16cycle not equal to 0,
|
||||
* The prescaler timer period is prescalePeriod_N16Cycle * 16 clock cycles.
|
||||
* idleTimeout_NprescalePeriod, refreshUrgThreshold_NprescalePeriod, refreshPeriod_NprescalePeriod are
|
||||
* similar to prescalePeriod_N16Cycle.
|
||||
*
|
||||
*/
|
||||
typedef struct _semc_sdram_config
|
||||
{
|
||||
semc_iomux_pin csxPinMux; /*!< CS pin mux. The kSEMC_MUXA8 is not valid in sdram pin mux setting. */
|
||||
uint32_t address; /*!< The base address. */
|
||||
uint32_t memsize_kbytes; /*!< The memory size in unit of kbytes. */
|
||||
smec_port_size_t portSize; /*!< Port size. */
|
||||
sem_sdram_burst_len_t burstLen; /*!< Burst length. */
|
||||
semc_sdram_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */
|
||||
semc_caslatency_t casLatency; /*!< CAS latency. */
|
||||
uint8_t tPrecharge2Act_Ns; /*!< Precharge to active wait time in unit of nanosecond. */
|
||||
uint8_t tAct2ReadWrite_Ns; /*!< Act to read/write wait time in unit of nanosecond. */
|
||||
uint8_t tRefreshRecovery_Ns; /*!< Refresh recovery time in unit of nanosecond. */
|
||||
uint8_t tWriteRecovery_Ns; /*!< write recovery time in unit of nanosecond. */
|
||||
uint8_t tCkeOff_Ns; /*!< CKE off minimum time in unit of nanosecond. */
|
||||
uint8_t tAct2Prechage_Ns; /*!< Active to precharge in unit of nanosecond. */
|
||||
uint8_t tSelfRefRecovery_Ns; /*!< Self refresh recovery time in unit of nanosecond. */
|
||||
uint8_t tRefresh2Refresh_Ns; /*!< Refresh to refresh wait time in unit of nanosecond. */
|
||||
uint8_t tAct2Act_Ns; /*!< Active to active wait time in unit of nanosecond. */
|
||||
uint32_t tPrescalePeriod_Ns; /*!< Prescaler timer period should not be larger than 256 * 16 * clock cycle. */
|
||||
uint32_t tIdleTimeout_Ns; /*!< Idle timeout in unit of prescale time period. */
|
||||
uint32_t refreshPeriod_nsPerRow; /*!< Refresh timer period like 64ms * 1000000/8192 . */
|
||||
uint32_t refreshUrgThreshold; /*!< Refresh urgent threshold. */
|
||||
uint8_t refreshBurstLen; /*!< Refresh burst length. */
|
||||
} semc_sdram_config_t;
|
||||
|
||||
/*! @brief SEMC NAND device timing configuration structure. */
|
||||
typedef struct _semc_nand_timing_config
|
||||
{
|
||||
uint8_t tCeSetup_Ns; /*!< CE setup time: tCS. */
|
||||
uint8_t tCeHold_Ns; /*!< CE hold time: tCH. */
|
||||
uint8_t tCeInterval_Ns; /*!< CE interval time:tCEITV. */
|
||||
uint8_t tWeLow_Ns; /*!< WE low time: tWP. */
|
||||
uint8_t tWeHigh_Ns; /*!< WE high time: tWH. */
|
||||
uint8_t tReLow_Ns; /*!< RE low time: tRP. */
|
||||
uint8_t tReHigh_Ns; /*!< RE high time: tREH. */
|
||||
uint8_t tTurnAround_Ns; /*!< Turnaround time for async mode: tTA. */
|
||||
uint8_t tWehigh2Relow_Ns; /*!< WE# high to RE# wait time: tWHR. */
|
||||
uint8_t tRehigh2Welow_Ns; /*!< RE# high to WE# low wait time: tRHW. */
|
||||
uint8_t tAle2WriteStart_Ns; /*!< ALE to write start wait time: tADL. */
|
||||
uint8_t tReady2Relow_Ns; /*!< Ready to RE# low min wait time: tRR. */
|
||||
uint8_t tWehigh2Busy_Ns; /*!< WE# high to busy wait time: tWB. */
|
||||
} semc_nand_timing_config_t;
|
||||
|
||||
/*! @brief SEMC NAND configuration structure. */
|
||||
typedef struct _semc_nand_config
|
||||
{
|
||||
semc_iomux_pin cePinMux; /*!< The CE pin mux setting. The kSEMC_MUXRDY is not valid for CE pin setting. */
|
||||
uint32_t axiAddress; /*!< The base address for AXI nand. */
|
||||
uint32_t axiMemsize_kbytes; /*!< The memory size in unit of kbytes for AXI nand. */
|
||||
uint32_t ipgAddress; /*!< The base address for IPG nand . */
|
||||
uint32_t ipgMemsize_kbytes; /*!< The memory size in unit of kbytes for IPG nand. */
|
||||
semc_rdy_polarity_t rdyactivePolarity; /*!< Wait ready polarity. */
|
||||
bool edoModeEnabled; /*!< EDO mode enabled. */
|
||||
semc_nand_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */
|
||||
semc_nand_address_option_t arrayAddrOption; /*!< Address option. */
|
||||
sem_nand_burst_len_t burstLen; /*!< Burst length. */
|
||||
smec_port_size_t portSize; /*!< Port size. */
|
||||
semc_nand_timing_config_t *timingConfig; /*!< SEMC nand timing configuration. */
|
||||
} semc_nand_config_t;
|
||||
|
||||
/*! @brief SEMC NOR configuration structure. */
|
||||
typedef struct _semc_nor_config
|
||||
{
|
||||
semc_iomux_pin cePinMux; /*!< The CE# pin mux setting. */
|
||||
semc_iomux_nora27_pin addr27; /*!< The Addr bit 27 pin mux setting. */
|
||||
uint32_t address; /*!< The base address. */
|
||||
uint32_t memsize_kbytes; /*!< The memory size in unit of kbytes. */
|
||||
uint8_t addrPortWidth; /*!< The address port width. */
|
||||
semc_rdy_polarity_t rdyactivePolarity; /*!< Wait ready polarity. */
|
||||
semc_adv_polarity_t advActivePolarity; /*!< ADV# polarity. */
|
||||
semc_norsram_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */
|
||||
semc_addr_mode_t addrMode; /*!< Address mode. */
|
||||
sem_norsram_burst_len_t burstLen; /*!< Burst length. */
|
||||
smec_port_size_t portSize; /*!< Port size. */
|
||||
uint8_t tCeSetup_Ns; /*!< The CE setup time. */
|
||||
uint8_t tCeHold_Ns; /*!< The CE hold time. */
|
||||
uint8_t tCeInterval_Ns; /*!< CE interval minimum time. */
|
||||
uint8_t tAddrSetup_Ns; /*!< The address setup time. */
|
||||
uint8_t tAddrHold_Ns; /*!< The address hold time. */
|
||||
uint8_t tWeLow_Ns; /*!< WE low time for async mode. */
|
||||
uint8_t tWeHigh_Ns; /*!< WE high time for async mode. */
|
||||
uint8_t tReLow_Ns; /*!< RE low time for async mode. */
|
||||
uint8_t tReHigh_Ns; /*!< RE high time for async mode. */
|
||||
uint8_t tTurnAround_Ns; /*!< Turnaround time for async mode. */
|
||||
uint8_t tAddr2WriteHold_Ns; /*!< Address to write data hold time for async mode. */
|
||||
#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME)
|
||||
uint8_t tWriteSetup_Ns; /*!< Write data setup time for sync mode.*/
|
||||
#endif
|
||||
#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME)
|
||||
uint8_t tWriteHold_Ns; /*!< Write hold time for sync mode. */
|
||||
#endif
|
||||
uint8_t latencyCount; /*!< Latency count for sync mode. */
|
||||
uint8_t readCycle; /*!< Read cycle time for sync mode. */
|
||||
} semc_nor_config_t;
|
||||
|
||||
/*! @brief SEMC SRAM configuration structure. */
|
||||
typedef struct _semc_sram_config
|
||||
{
|
||||
semc_iomux_pin cePinMux; /*!< The CE# pin mux setting. */
|
||||
semc_iomux_nora27_pin addr27; /*!< The Addr bit 27 pin mux setting. */
|
||||
uint32_t address; /*!< The base address. */
|
||||
uint32_t memsize_kbytes; /*!< The memory size in unit of kbytes. */
|
||||
uint8_t addrPortWidth; /*!< The address port width. */
|
||||
semc_adv_polarity_t advActivePolarity; /*!< ADV# polarity 1: active high, 0: active low. */
|
||||
semc_addr_mode_t addrMode; /*!< Address mode. */
|
||||
sem_norsram_burst_len_t burstLen; /*!< Burst length. */
|
||||
smec_port_size_t portSize; /*!< Port size. */
|
||||
uint8_t tCeSetup_Ns; /*!< The CE setup time. */
|
||||
uint8_t tCeHold_Ns; /*!< The CE hold time. */
|
||||
uint8_t tCeInterval_Ns; /*!< CE interval minimum time. */
|
||||
uint8_t tAddrSetup_Ns; /*!< The address setup time. */
|
||||
uint8_t tAddrHold_Ns; /*!< The address hold time. */
|
||||
uint8_t tWeLow_Ns; /*!< WE low time for async mode. */
|
||||
uint8_t tWeHigh_Ns; /*!< WE high time for async mode. */
|
||||
uint8_t tReLow_Ns; /*!< RE low time for async mode. */
|
||||
uint8_t tReHigh_Ns; /*!< RE high time for async mode. */
|
||||
uint8_t tTurnAround_Ns; /*!< Turnaround time for async mode. */
|
||||
uint8_t tAddr2WriteHold_Ns; /*!< Address to write data hold time for async mode. */
|
||||
uint8_t tWriteSetup_Ns; /*!< Write data setup time for sync mode.*/
|
||||
uint8_t tWriteHold_Ns; /*!< Write hold time for sync mode. */
|
||||
uint8_t latencyCount; /*!< Latency count for sync mode. */
|
||||
uint8_t readCycle; /*!< Read cycle time for sync mode. */
|
||||
} semc_sram_config_t;
|
||||
|
||||
/*! @brief SEMC DBI configuration structure. */
|
||||
typedef struct _semc_dbi_config
|
||||
{
|
||||
semc_iomux_pin csxPinMux; /*!< The CE# pin mux. */
|
||||
uint32_t address; /*!< The base address. */
|
||||
uint32_t memsize_kbytes; /*!< The memory size in unit of 4kbytes. */
|
||||
semc_dbi_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */
|
||||
sem_dbi_burst_len_t burstLen; /*!< Burst length. */
|
||||
smec_port_size_t portSize; /*!< Port size. */
|
||||
uint8_t tCsxSetup_Ns; /*!< The CSX setup time. */
|
||||
uint8_t tCsxHold_Ns; /*!< The CSX hold time. */
|
||||
uint8_t tWexLow_Ns; /*!< WEX low time. */
|
||||
uint8_t tWexHigh_Ns; /*!< WEX high time. */
|
||||
uint8_t tRdxLow_Ns; /*!< RDX low time. */
|
||||
uint8_t tRdxHigh_Ns; /*!< RDX high time. */
|
||||
uint8_t tCsxInterval_Ns; /*!< Write data setup time.*/
|
||||
} semc_dbi_config_t;
|
||||
|
||||
/*! @brief SEMC AXI queue a weight setting structure. */
|
||||
typedef struct _semc_queuea_weight_struct
|
||||
{
|
||||
uint32_t qos : 4; /*!< weight of qos for queue 0 . */
|
||||
uint32_t aging : 4; /*!< weight of aging for queue 0.*/
|
||||
uint32_t slaveHitSwith : 8; /*!< weight of read/write switch for queue 0.*/
|
||||
uint32_t slaveHitNoswitch : 8; /*!< weight of read/write no switch for queue 0 .*/
|
||||
} semc_queuea_weight_struct_t;
|
||||
|
||||
/*! @brief SEMC AXI queue a weight setting union. */
|
||||
typedef union _semc_queuea_weight
|
||||
{
|
||||
semc_queuea_weight_struct_t queueaConfig; /*!< Structure configuration for queueA. */
|
||||
uint32_t queueaValue; /*!< Configuration value for queueA which could directly write to the reg. */
|
||||
} semc_queuea_weight_t;
|
||||
|
||||
/*! @brief SEMC AXI queue b weight setting structure. */
|
||||
typedef struct _semc_queueb_weight_struct
|
||||
{
|
||||
uint32_t qos : 4; /*!< weight of qos for queue 1. */
|
||||
uint32_t aging : 4; /*!< weight of aging for queue 1.*/
|
||||
uint32_t slaveHitSwith : 8; /*!< weight of read/write switch for queue 1.*/
|
||||
uint32_t weightPagehit : 8; /*!< weight of page hit for queue 1 only .*/
|
||||
uint32_t bankRotation : 8; /*!< weight of bank rotation for queue 1 only .*/
|
||||
} semc_queueb_weight_struct_t;
|
||||
|
||||
/*! @brief SEMC AXI queue b weight setting union. */
|
||||
typedef union _semc_queueb_weight
|
||||
{
|
||||
semc_queueb_weight_struct_t queuebConfig; /*!< Structure configuration for queueB. */
|
||||
uint32_t queuebValue; /*!< Configuration value for queueB which could directly write to the reg. */
|
||||
} semc_queueb_weight_t;
|
||||
|
||||
/*! @brief SEMC AXI queue weight setting. */
|
||||
typedef struct _semc_axi_queueweight
|
||||
{
|
||||
semc_queuea_weight_t queueaWeight; /*!< Weight settings for queue a. */
|
||||
semc_queueb_weight_t queuebWeight; /*!< Weight settings for queue b. */
|
||||
} semc_axi_queueweight_t;
|
||||
|
||||
/*!
|
||||
* @brief SEMC configuration structure.
|
||||
*
|
||||
* busTimeoutCycles: when busTimeoutCycles is zero, the bus timeout cycle is
|
||||
* 255*1024. otherwise the bus timeout cycles is busTimeoutCycles*1024.
|
||||
* cmdTimeoutCycles: is used for command execution timeout cycles. it's
|
||||
* similar to the busTimeoutCycles.
|
||||
*/
|
||||
typedef struct _semc_config_t
|
||||
{
|
||||
semc_dqs_mode_t dqsMode; /*!< Dummy read strobe mode: use enum in "semc_dqs_mode_t". */
|
||||
uint8_t cmdTimeoutCycles; /*!< Command execution timeout cycles. */
|
||||
uint8_t busTimeoutCycles; /*!< Bus timeout cycles. */
|
||||
semc_axi_queueweight_t queueWeight; /*!< AXI queue weight. */
|
||||
} semc_config_t;
|
||||
|
||||
/*******************************************************************************
|
||||
* API
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @name SEMC Initialization and De-initialization
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Gets the SEMC default basic configuration structure.
|
||||
*
|
||||
* The purpose of this API is to get the default SEMC
|
||||
* configure structure for SEMC_Init(). User may use the initialized
|
||||
* structure unchanged in SEMC_Init(), or modify some fields of the
|
||||
* structure before calling SEMC_Init().
|
||||
* Example:
|
||||
@code
|
||||
semc_config_t config;
|
||||
SEMC_GetDefaultConfig(&config);
|
||||
@endcode
|
||||
* @param config The SEMC configuration structure pointer.
|
||||
*/
|
||||
void SEMC_GetDefaultConfig(semc_config_t *config);
|
||||
|
||||
/*!
|
||||
* @brief Initializes SEMC.
|
||||
* This function ungates the SEMC clock and initializes SEMC.
|
||||
* This function must be called before calling any other SEMC driver functions.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param configure The SEMC configuration structure pointer.
|
||||
*/
|
||||
void SEMC_Init(SEMC_Type *base, semc_config_t *configure);
|
||||
|
||||
/*!
|
||||
* @brief Deinitializes the SEMC module and gates the clock.
|
||||
*
|
||||
* This function gates the SEMC clock. As a result, the SEMC module doesn't work after
|
||||
* calling this function, for some IDE, calling this API may cause the next downloading
|
||||
* operation failed. so, please call this API cautiously. Additional, users can
|
||||
* using "#define FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL (1)" to disable the clock control
|
||||
* operation in drivers.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
*/
|
||||
void SEMC_Deinit(SEMC_Type *base);
|
||||
|
||||
/* @} */
|
||||
|
||||
/*!
|
||||
* @name SEMC Configuration Operation For Each Memory Type
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Configures SDRAM controller in SEMC.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param cs The chip selection.
|
||||
* @param config The sdram configuration.
|
||||
* @param clkSrc_Hz The SEMC clock frequency.
|
||||
*/
|
||||
status_t SEMC_ConfigureSDRAM(SEMC_Type *base, semc_sdram_cs_t cs, semc_sdram_config_t *config, uint32_t clkSrc_Hz);
|
||||
|
||||
/*!
|
||||
* @brief Configures NAND controller in SEMC.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param config The nand configuration.
|
||||
* @param clkSrc_Hz The SEMC clock frequency.
|
||||
*/
|
||||
status_t SEMC_ConfigureNAND(SEMC_Type *base, semc_nand_config_t *config, uint32_t clkSrc_Hz);
|
||||
|
||||
/*!
|
||||
* @brief Configures NOR controller in SEMC.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param config The nor configuration.
|
||||
* @param clkSrc_Hz The SEMC clock frequency.
|
||||
*/
|
||||
status_t SEMC_ConfigureNOR(SEMC_Type *base, semc_nor_config_t *config, uint32_t clkSrc_Hz);
|
||||
|
||||
/*!
|
||||
* @brief Configures SRAM controller in SEMC.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param config The sram configuration.
|
||||
* @param clkSrc_Hz The SEMC clock frequency.
|
||||
*/
|
||||
status_t SEMC_ConfigureSRAM(SEMC_Type *base, semc_sram_config_t *config, uint32_t clkSrc_Hz);
|
||||
|
||||
/*!
|
||||
* @brief Configures DBI controller in SEMC.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param config The dbi configuration.
|
||||
* @param clkSrc_Hz The SEMC clock frequency.
|
||||
*/
|
||||
status_t SEMC_ConfigureDBI(SEMC_Type *base, semc_dbi_config_t *config, uint32_t clkSrc_Hz);
|
||||
|
||||
/* @} */
|
||||
|
||||
/*!
|
||||
* @name SEMC Interrupt Operation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Enables the SEMC interrupt.
|
||||
*
|
||||
* This function enables the SEMC interrupts according to the provided mask. The mask
|
||||
* is a logical OR of enumeration members. See @ref semc_interrupt_enable_t.
|
||||
* For example, to enable the IP command done and error interrupt, do the following.
|
||||
* @code
|
||||
* SEMC_EnableInterrupts(ENET, kSEMC_IPCmdDoneInterrupt | kSEMC_IPCmdErrInterrupt);
|
||||
* @endcode
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param mask SEMC interrupts to enable. This is a logical OR of the
|
||||
* enumeration :: semc_interrupt_enable_t.
|
||||
*/
|
||||
static inline void SEMC_EnableInterrupts(SEMC_Type *base, uint32_t mask)
|
||||
{
|
||||
base->INTEN |= mask;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Disables the SEMC interrupt.
|
||||
*
|
||||
* This function disables the SEMC interrupts according to the provided mask. The mask
|
||||
* is a logical OR of enumeration members. See @ref semc_interrupt_enable_t.
|
||||
* For example, to disable the IP command done and error interrupt, do the following.
|
||||
* @code
|
||||
* SEMC_DisableInterrupts(ENET, kSEMC_IPCmdDoneInterrupt | kSEMC_IPCmdErrInterrupt);
|
||||
* @endcode
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param mask SEMC interrupts to disable. This is a logical OR of the
|
||||
* enumeration :: semc_interrupt_enable_t.
|
||||
*/
|
||||
static inline void SEMC_DisableInterrupts(SEMC_Type *base, uint32_t mask)
|
||||
{
|
||||
base->INTEN &= ~mask;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Gets the SEMC status.
|
||||
*
|
||||
* This function gets the SEMC interrupts event status.
|
||||
* User can use the a logical OR of enumeration member as a mask.
|
||||
* See @ref semc_interrupt_enable_t.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @return status flag, use status flag in semc_interrupt_enable_t to get the related status.
|
||||
*/
|
||||
static inline bool SEMC_GetStatusFlag(SEMC_Type *base)
|
||||
{
|
||||
return base->INTR;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Clears the SEMC status flag state.
|
||||
*
|
||||
* The following status register flags can be cleared SEMC interrupt status.
|
||||
*
|
||||
* @param base SEMC base pointer
|
||||
* @param mask The status flag mask, a logical OR of enumeration member @ref semc_interrupt_enable_t.
|
||||
*/
|
||||
static inline void SEMC_ClearStatusFlags(SEMC_Type *base, uint32_t mask)
|
||||
{
|
||||
base->INTR |= mask;
|
||||
}
|
||||
|
||||
/* @} */
|
||||
|
||||
/*!
|
||||
* @name SEMC Memory Access Operation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Check if SEMC is in idle.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @return True SEMC is in idle, false is not in idle.
|
||||
*/
|
||||
static inline bool SEMC_IsInIdle(SEMC_Type *base)
|
||||
{
|
||||
return (base->STS0 & SEMC_STS0_IDLE_MASK) ? true : false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief SEMC IP command access.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param type SEMC memory type. refer to "semc_mem_type_t"
|
||||
* @param address SEMC device address.
|
||||
* @param command SEMC IP command.
|
||||
* For NAND device, we should use the SEMC_BuildNandIPCommand to get the right nand command.
|
||||
* For NOR/DBI device, take refer to "semc_ipcmd_nor_dbi_t".
|
||||
* For SRAM device, take refer to "semc_ipcmd_sram_t".
|
||||
* For SDRAM device, take refer to "semc_ipcmd_sdram_t".
|
||||
* @param write Data for write access.
|
||||
* @param read Data pointer for read data out.
|
||||
*/
|
||||
status_t SEMC_SendIPCommand(
|
||||
SEMC_Type *base, semc_mem_type_t type, uint32_t address, uint16_t command, uint32_t write, uint32_t *read);
|
||||
|
||||
/*!
|
||||
* @brief Build SEMC IP command for NAND.
|
||||
*
|
||||
* This function build SEMC NAND IP command. The command is build of user command code,
|
||||
* SEMC address mode and SEMC command mode.
|
||||
*
|
||||
* @param userCommand NAND device normal command.
|
||||
* @param addrMode NAND address mode. Refer to "semc_ipcmd_nand_addrmode_t".
|
||||
* @param cmdMode NAND command mode. Refer to "semc_ipcmd_nand_cmdmode_t".
|
||||
*/
|
||||
static inline uint16_t SEMC_BuildNandIPCommand(uint8_t userCommand,
|
||||
semc_ipcmd_nand_addrmode_t addrMode,
|
||||
semc_ipcmd_nand_cmdmode_t cmdMode)
|
||||
{
|
||||
return (uint16_t)((uint16_t)userCommand << 8) | (uint16_t)(addrMode << 4) | ((uint8_t)cmdMode & 0x0Fu);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check if the NAND device is ready.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @return True NAND is ready, false NAND is not ready.
|
||||
*/
|
||||
static inline bool SEMC_IsNandReady(SEMC_Type *base)
|
||||
{
|
||||
return (base->STS0 & SEMC_STS0_NARDY_MASK) ? true : false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief SEMC NAND device memory write through IP command.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param address SEMC NAND device address.
|
||||
* @param data Data for write access.
|
||||
* @param size_bytes Data length.
|
||||
*/
|
||||
status_t SEMC_IPCommandNandWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes);
|
||||
|
||||
/*!
|
||||
* @brief SEMC NAND device memory read through IP command.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param address SEMC NAND device address.
|
||||
* @param data Data pointer for data read out.
|
||||
* @param size_bytes Data length.
|
||||
*/
|
||||
status_t SEMC_IPCommandNandRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes);
|
||||
|
||||
/*!
|
||||
* @brief SEMC NOR device memory write through IP command.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param address SEMC NOR device address.
|
||||
* @param data Data for write access.
|
||||
* @param size_bytes Data length.
|
||||
*/
|
||||
status_t SEMC_IPCommandNorWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes);
|
||||
|
||||
/*!
|
||||
* @brief SEMC NOR device memory read through IP command.
|
||||
*
|
||||
* @param base SEMC peripheral base address.
|
||||
* @param address SEMC NOR device address.
|
||||
* @param data Data pointer for data read out.
|
||||
* @param size_bytes Data length.
|
||||
*/
|
||||
status_t SEMC_IPCommandNorRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes);
|
||||
|
||||
/* @} */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! @}*/
|
||||
|
||||
#endif /* _FSL_SEMC_H_*/
|
|
@ -0,0 +1,9 @@
|
|||
config BSP_USING_EXTSRAM
|
||||
bool "config semc extern sram"
|
||||
default n
|
||||
select MEM_EXTERN_SRAM
|
||||
if BSP_USING_EXTSRAM
|
||||
config EXTSRAM_MAX_NUM
|
||||
int "config extsram chip num"
|
||||
default 4
|
||||
endif
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := connect_semc.c fsl_semc.c semc_externsdram_test.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,57 @@
|
|||
#include "fsl_semc.h"
|
||||
#include "clock_config.h"
|
||||
#include <xs_base.h>
|
||||
|
||||
#define EXAMPLE_SEMC SEMC
|
||||
#define EXAMPLE_SEMC_START_ADDRESS (0x80000000U)
|
||||
#define EXAMPLE_SEMC_CLK_FREQ CLOCK_GetFreq(kCLOCK_SemcClk)
|
||||
#define SEMC_SRAM_SIZE (32 * 1024 * 1024)
|
||||
|
||||
status_t BOARD_InitSEMC(void)
|
||||
{
|
||||
semc_config_t config;
|
||||
semc_sdram_config_t sdramconfig;
|
||||
uint32_t clockFrq = EXAMPLE_SEMC_CLK_FREQ;
|
||||
|
||||
/* Initializes the MAC configure structure to zero. */
|
||||
memset(&config, 0, sizeof(semc_config_t));
|
||||
memset(&sdramconfig, 0, sizeof(semc_sdram_config_t));
|
||||
|
||||
/* Initialize SEMC. */
|
||||
SEMC_GetDefaultConfig(&config);
|
||||
config.dqsMode = kSEMC_Loopbackdqspad; /* For more accurate timing. */
|
||||
SEMC_Init(SEMC, &config);
|
||||
|
||||
/* Configure SDRAM. */
|
||||
sdramconfig.csxPinMux = kSEMC_MUXCSX0;
|
||||
sdramconfig.address = 0x80000000;
|
||||
sdramconfig.memsize_kbytes = 32 * 1024; /* 32MB = 32*1024*1KBytes*/
|
||||
sdramconfig.portSize = kSEMC_PortSize16Bit;
|
||||
sdramconfig.burstLen = kSEMC_Sdram_BurstLen8;
|
||||
sdramconfig.columnAddrBitNum = kSEMC_SdramColunm_9bit;
|
||||
sdramconfig.casLatency = kSEMC_LatencyThree;
|
||||
sdramconfig.tPrecharge2Act_Ns = 18; /* Trp 18ns */
|
||||
sdramconfig.tAct2ReadWrite_Ns = 18; /* Trcd 18ns */
|
||||
sdramconfig.tRefreshRecovery_Ns = 67; /* Use the maximum of the (Trfc , Txsr). */
|
||||
sdramconfig.tWriteRecovery_Ns = 12; /* 12ns */
|
||||
sdramconfig.tCkeOff_Ns =
|
||||
42; /* The minimum cycle of SDRAM CLK off state. CKE is off in self refresh at a minimum period tRAS.*/
|
||||
sdramconfig.tAct2Prechage_Ns = 42; /* Tras 42ns */
|
||||
sdramconfig.tSelfRefRecovery_Ns = 67;
|
||||
sdramconfig.tRefresh2Refresh_Ns = 60;
|
||||
sdramconfig.tAct2Act_Ns = 60;
|
||||
sdramconfig.tPrescalePeriod_Ns = 160 * (1000000000 / clockFrq);
|
||||
sdramconfig.refreshPeriod_nsPerRow = 64 * 1000000 / 8192; /* 64ms/8192 */
|
||||
sdramconfig.refreshUrgThreshold = sdramconfig.refreshPeriod_nsPerRow;
|
||||
sdramconfig.refreshBurstLen = 1;
|
||||
return SEMC_ConfigureSDRAM(SEMC, kSEMC_SDRAM_CS0, &sdramconfig, clockFrq);
|
||||
}
|
||||
|
||||
#ifdef BSP_USING_EXTSRAM
|
||||
int ExtSramInit(void)
|
||||
{
|
||||
extern void ExtSramInitBoardMemory(void *start_phy_address, void *end_phy_address, uint8 extsram_idx);
|
||||
ExtSramInitBoardMemory((void*)(EXAMPLE_SEMC_START_ADDRESS), (void*)((EXAMPLE_SEMC_START_ADDRESS + SEMC_SRAM_SIZE)), kSEMC_SDRAM_CS0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright 2017 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include "board.h"
|
||||
|
||||
#define EXAMPLE_SEMC_START_ADDRESS (0x80000000U)
|
||||
|
||||
#define SEMC_EXAMPLE_DATALEN (0x1000U)
|
||||
|
||||
/*******************************************************************************
|
||||
* Prototypes
|
||||
******************************************************************************/
|
||||
static void SEMC_SDRAMReadWrite32Bit(void);
|
||||
static void SEMC_SDRAMReadWrite16Bit(void);
|
||||
static void SEMC_SDRAMReadWrite8Bit(void);
|
||||
/*******************************************************************************
|
||||
* Variables
|
||||
******************************************************************************/
|
||||
|
||||
uint32_t sdram_writeBuffer[SEMC_EXAMPLE_DATALEN];
|
||||
uint32_t sdram_readBuffer[SEMC_EXAMPLE_DATALEN];
|
||||
|
||||
/*!
|
||||
* @brief Main function
|
||||
*/
|
||||
int semc_externsram_test(void)
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM Example Start!\r\n");
|
||||
|
||||
/* 32Bit data read and write. */
|
||||
SEMC_SDRAMReadWrite32Bit();
|
||||
/* 16Bit data read and write. */
|
||||
SEMC_SDRAMReadWrite16Bit();
|
||||
/* 8Bit data read and write. */
|
||||
SEMC_SDRAMReadWrite8Bit();
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Example End.\r\n");
|
||||
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),semc_externsram_test, semc_externsram_test, semc_externsram_test );
|
||||
|
||||
void SEMC_SDRAMReadWrite32Bit(void)
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t datalen = SEMC_EXAMPLE_DATALEN;
|
||||
uint32_t *sdram = (uint32_t *)EXAMPLE_SEMC_START_ADDRESS; /* SDRAM start address. */
|
||||
int result = 0;
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Memory 32 bit Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen);
|
||||
/* Prepare data and write to SDRAM. */
|
||||
for (index = 0; index < datalen; index++)
|
||||
{
|
||||
sdram_writeBuffer[index] = index;
|
||||
sdram[index] = sdram_writeBuffer[index];
|
||||
}
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Read 32 bit Data Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen);
|
||||
/* Read data from the SDRAM. */
|
||||
for (index = 0; index < datalen; index++)
|
||||
{
|
||||
sdram_readBuffer[index] = sdram[index];
|
||||
}
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM 32 bit Data Write and Read Compare Start!\r\n");
|
||||
/* Compare the two buffers. */
|
||||
while (datalen--)
|
||||
{
|
||||
if (sdram_writeBuffer[datalen] != sdram_readBuffer[datalen])
|
||||
{
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM 32 bit Data Write and Read Compare Failed!\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM 32 bit Data Write and Read Compare Succeed!\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void SEMC_SDRAMReadWrite16Bit(void)
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t datalen = SEMC_EXAMPLE_DATALEN;
|
||||
uint16_t *sdram = (uint16_t *)EXAMPLE_SEMC_START_ADDRESS; /* SDRAM start address. */
|
||||
int result = 0;
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Memory 16 bit Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen);
|
||||
|
||||
memset(sdram_writeBuffer, 0, sizeof(sdram_writeBuffer));
|
||||
memset(sdram_readBuffer, 0, sizeof(sdram_readBuffer));
|
||||
|
||||
/* Prepare data and write to SDRAM. */
|
||||
for (index = 0; index < datalen; index++)
|
||||
{
|
||||
sdram_writeBuffer[index] = index % 0xFFFF;
|
||||
sdram[index] = sdram_writeBuffer[index];
|
||||
}
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Read 16 bit Data Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen);
|
||||
/* Read data from the SDRAM. */
|
||||
for (index = 0; index < datalen; index++)
|
||||
{
|
||||
sdram_readBuffer[index] = sdram[index];
|
||||
}
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM 16 bit Data Write and Read Compare Start!\r\n");
|
||||
/* Compare the two buffers. */
|
||||
while (datalen--)
|
||||
{
|
||||
if (sdram_writeBuffer[datalen] != sdram_readBuffer[datalen])
|
||||
{
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM 16 bit Data Write and Read Compare Failed!\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM 16 bit Data Write and Read Compare Succeed!\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void SEMC_SDRAMReadWrite8Bit(void)
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t datalen = SEMC_EXAMPLE_DATALEN;
|
||||
uint8_t *sdram = (uint8_t *)EXAMPLE_SEMC_START_ADDRESS; /* SDRAM start address. */
|
||||
int result = 0;
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Memory 8 bit Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen);
|
||||
|
||||
memset(sdram_writeBuffer, 0, sizeof(sdram_writeBuffer));
|
||||
memset(sdram_readBuffer, 0, sizeof(sdram_readBuffer));
|
||||
|
||||
/* Prepare data and write to SDRAM. */
|
||||
for (index = 0; index < datalen; index++)
|
||||
{
|
||||
sdram_writeBuffer[index] = index % 0x100;
|
||||
sdram[index] = sdram_writeBuffer[index];
|
||||
}
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM Read 8 bit Data Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen);
|
||||
/* Read data from the SDRAM. */
|
||||
for (index = 0; index < datalen; index++)
|
||||
{
|
||||
sdram_readBuffer[index] = sdram[index];
|
||||
}
|
||||
|
||||
KPrintf("\r\n SEMC SDRAM 8 bit Data Write and Read Compare Start!\r\n");
|
||||
/* Compare the two buffers. */
|
||||
while (datalen--)
|
||||
{
|
||||
if (sdram_writeBuffer[datalen] != sdram_readBuffer[datalen])
|
||||
{
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM 8 bit Data Write and Read Compare Failed!\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("\r\n SEMC SDRAM 8 bit Data Write and Read Compare Succeed!\r\n");
|
||||
}
|
||||
}
|
|
@ -13,10 +13,21 @@ KERNELPATHS :=-I$(BSP_ROOT) \
|
|||
-I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/include \
|
||||
-I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/osa \
|
||||
-I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/phy \
|
||||
-I$(BSP_ROOT)/third_party_driver/ethernet \
|
||||
-I$(BSP_ROOT)/third_party_driver/ethernet/ksz8081 \
|
||||
-I$(BSP_ROOT)/third_party_driver/MIMXRT1052 \
|
||||
-I$(BSP_ROOT)/third_party_driver/MIMXRT1052/drivers \
|
||||
-I$(BSP_ROOT)/third_party_driver/CMSIS/Include \
|
||||
-I$(KERNEL_ROOT)/include \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/compat \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/netif \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip/apps \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip/priv \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip/prot \
|
||||
-I$(KERNEL_ROOT)/resources/ethernet/LwIP/arch \
|
||||
-I$(KERNEL_ROOT)/resources/include \
|
||||
-I$(BSP_ROOT)/include \
|
||||
-I$(BSP_ROOT)/xip #
|
||||
|
|
Loading…
Reference in New Issue