optimize lwip demo and ok1052-c directories

This commit is contained in:
wlyu
2021-12-30 11:20:36 +08:00
parent 8fa0d977a0
commit 62dcbef383
61 changed files with 1006 additions and 470 deletions
@@ -1,3 +1,3 @@
SRC_FILES := enet_ethernetif.c enet_ethernetif_kinetis.c
SRC_FILES := enet_ethernetif.c enet_ethernetif_kinetis.c fsl_enet.c
SRC_DIR := ksz8081
include $(KERNEL_ROOT)/compiler.mk
@@ -206,6 +206,7 @@ void ethernetif_phy_init(struct ethernetif *ethernetif,
void ethernetif_input(struct netif *netif)
{
struct pbuf *p;
err_t ret = 0;
LWIP_ASSERT("netif != NULL", (netif != NULL));
@@ -213,9 +214,10 @@ void ethernetif_input(struct netif *netif)
while ((p = ethernetif_linkinput(netif)) != NULL)
{
/* pass all packets to ethernet_input, which decides what packets it supports */
if (netif->input(p, netif) != ERR_OK)
if ((ret = netif->input(p, netif)) != ERR_OK)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
// 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;
}
@@ -287,7 +289,7 @@ err_t ethernetif_init(struct netif *netif, struct ethernetif *ethernetif,
/* Init ethernetif parameters.*/
*ethernetif_enet_ptr(ethernetif) = ethernetif_get_enet_base(enetIdx);
// LWIP_ASSERT("*ethernetif_enet_ptr(ethernetif) != NULL", (*ethernetif_enet_ptr(ethernetif) != NULL));
LWIP_ASSERT("*ethernetif_enet_ptr(ethernetif) != NULL", (*ethernetif_enet_ptr(ethernetif) != NULL));
/* set MAC hardware address length */
netif->hwaddr_len = ETH_HWADDR_LEN;
@@ -1,202 +0,0 @@
/*
* 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
*/
/*
* 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 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 (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);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* ENET_ETHERNETIF_H */
@@ -70,29 +70,39 @@
#include "lwip/igmp.h"
#include "lwip/mld6.h"
//
//#define USE_RTOS 1
//#define FSL_RTOS_FREE_RTOS
//#define FSL_RTOS_XIUOS
#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
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
typedef TickType_t EventBits_t;
typedef TickType_t EventBits_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#define portBASE_TYPE long
#define portBASE_TYPE long
#define pdFALSE ( ( BaseType_t ) 0 )
#define pdTRUE ( ( BaseType_t ) 1 )
#define pdPASS ( pdTRUE )
#define pdFAIL ( pdFALSE )
#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;
@@ -109,7 +119,7 @@ typedef struct EventGroupDef_t
struct EventGroupDef_t;
typedef struct EventGroupDef_t * EventGroupHandle_t;
#endif
#endif
@@ -121,6 +131,8 @@ typedef struct EventGroupDef_t * EventGroupHandle_t;
#include "sys_arch.h"
/*******************************************************************************
* Definitions
******************************************************************************/
@@ -136,7 +148,12 @@ struct ethernetif
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;
@@ -161,6 +178,8 @@ static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event
BaseType_t xResult;
lw_print("lw: [%s] input event %#x \n", __func__, event);
switch (event)
{
case kENET_RxEvent:
@@ -170,6 +189,9 @@ static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event
{
portBASE_TYPE taskToWake = pdFALSE;
#ifdef FSL_RTOS_XIUOS
#else
#ifdef __CA7_REV
if (SystemGetIRQNestingLevel())
#else
@@ -186,11 +208,14 @@ static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event
{
xEventGroupSetBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag);
}
#endif
}
break;
default:
break;
}
KSemaphoreAbandon(ethernetif->enetSemaphore);
}
#endif
@@ -274,6 +299,56 @@ err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group,
}
#endif
#define netifINTERFACE_TASK_STACK_SIZE ( 4096 )
/**
* This function is the ethernetif_input task, it is processed when a packet
* is ready to be read from the interface. It uses the function low_level_input()
* 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 eth_input( void * pvParameters )
//{
// struct pbuf *p;
//
// for( ;; )
// {
// if (KSemaphoreObtain( s_xSemaphore, WAITING_FOREVER)==EOK)
// {
// p = low_level_input( s_pxNetIf );
//
// if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
// {
// KPrintf("netif input return not OK ! \n");
// pbuf_free(p);
// p=NULL;
// }
// }
// }
//}
//
//void low_level_init()
//{
// /* create the task that handles the ETH_MAC */
// uint32 thr_id = KTaskCreate((signed char*) "eth_input",
// eth_input,
// NULL,
// netifINTERFACE_TASK_STACK_SIZE,
// 15);
// if (thr_id >= 0)
// {
// StartupKTask(thr_id);
// }
// else
// {
// KPrintf("Eth create failed !");
// }
//}
/**
* Initializes ENET driver.
*/
@@ -313,7 +388,14 @@ void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif,
#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;
@@ -350,6 +432,7 @@ void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif,
#endif
ENET_ActiveRead(ethernetif->base);
// low_level_init();
}
ENET_Type **ethernetif_enet_ptr(struct ethernetif *ethernetif)
@@ -376,17 +459,27 @@ static err_t enet_send_frame(struct ethernetif *ethernetif, unsigned char *data,
{
status_t result;
lw_print("lw: [%s] len %d\n", __func__, length);
do
{
result = ENET_SendFrame(ethernetif->base, &ethernetif->handle, data, length);
if (result == kStatus_ENET_TxFrameBusy)
{
#ifdef FSL_RTOS_XIUOS
// KSemaphoreObtain(ethernetif->enetSemaphore, portMAX_DELAY);
lw_trace();
#else
xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, pdTRUE, (BaseType_t) false,
portMAX_DELAY);
#endif
}
} while (result == kStatus_ENET_TxFrameBusy);
lw_trace();
return ERR_OK;
}
#else
@@ -1,94 +0,0 @@
/*
* Copyright 2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* 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 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 */
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,336 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2018 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* 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 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,221 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* 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 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_ */