rt-thread/bsp/phytium/libraries/standalone/drivers/eth/fgmac/fgmac.c

511 lines
16 KiB
C
Raw Normal View History

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fgmac.c
* Date: 2022-04-06 14:46:52
* LastEditTime: 2022-04-06 14:46:58
* Description:  This file is for gmac driver .Functions in this file are the minimum required functions
* for this driver.
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 huanghe 2021/07/13 first release
*/
/***************************** Include Files *********************************/
#include <string.h>
#include "fio.h"
#include "ferror_code.h"
#include "ftypes.h"
#include "fdebug.h"
#include "fassert.h"
#include "fgmac_hw.h"
#include "fgmac_phy.h"
#include "fgmac.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define FGMAC_DEBUG_TAG "FGMAC"
#define FGMAC_ERROR(format, ...) FT_DEBUG_PRINT_E(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FGMAC_WARN(format, ...) FT_DEBUG_PRINT_W(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FGMAC_INFO(format, ...) FT_DEBUG_PRINT_I(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FGMAC_DEBUG(format, ...) FT_DEBUG_PRINT_D(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
/************************** Function Prototypes ******************************/
static FError FGmacReset(FGmac *instance_p);
static FError FGmacDmaConfigure(FGmac *instance_p);
static FError FGmacControllerConfigure(FGmac *instance_p);
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/* 此文件主要为了完成用户对外接口,用户可以使用这些接口直接开始工作 */
/* - 包括用户API的定义和实现
- OPTION方法便
- I/O操作API */
/* - 包括用户API的定义和实现
- OPTION方法便
- I/O操作API */
/*
* @name: FGmacStop
* @msg: FGMAC控制器寄存器
* @return {*}
* @param {FGmac} *instance_p
*/
void FGmacStop(FGmac *instance_p)
{
FASSERT(instance_p);
uintptr base_addr = instance_p->config.base_addr;
u32 reg_val;
/* disable dma tx and rx */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_DMA_OP_OFFSET);
reg_val &= (~FGMAC_DMA_OP_ST);
reg_val &= (~FGMAC_DMA_OP_SR);
FGMAC_WRITE_REG32(base_addr, FGMAC_DMA_OP_OFFSET, reg_val);
/* disable gmac tx and rx */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_CONF_OFFSET);
reg_val &= (~FGMAC_CONF_TX_EN);
reg_val &= (~FGMAC_CONF_RX_EN);
FGMAC_WRITE_REG32(base_addr, FGMAC_CONF_OFFSET, reg_val);
}
/**
* @name: FGmacCfgInitialize
* @msg: init FGMAC controller
* @param {FGmac} *instance_p, instance of FGmac controller
* @param {FGmacConfig} *cofig_p, input configuration parameters
* @return err code information, FGMAC_SUCCESS indicates successothers indicates failed
*/
FError FGmacCfgInitialize(FGmac *instance_p, const FGmacConfig *input_config_p)
{
FASSERT(instance_p && input_config_p);
FError ret = FGMAC_SUCCESS;
/* indicating device is started */
if (FT_COMPONENT_IS_READY == instance_p->is_ready)
{
FGMAC_WARN("Device is already initialized!!!");
}
/* de-initialize device instance */
FGmacDeInitialize(instance_p);
instance_p->config = *input_config_p;
/* Phy Awaken */
ret = FGmacPhyAwaken(instance_p);
if (FGMAC_SUCCESS != ret)
{
FGMAC_ERROR("Phy awaken failed!");
return ret;
}
/* initialize the gmac controller */
ret = FGmacReset(instance_p);
if (FGMAC_SUCCESS != ret)
{
/*permit failed*/
FGMAC_ERROR("Gmac reset failed.");
}
ret = FGmacControllerConfigure(instance_p);
if (FGMAC_SUCCESS != ret)
{
return ret;
}
/* initialize the gmac dma controller */
ret = FGmacDmaConfigure(instance_p);
if (FGMAC_SUCCESS == ret)
{
instance_p->is_ready = FT_COMPONENT_IS_READY;
}
return ret;
}
/**
* @name: FGmacDeInitialize
* @msg: deinit FGMAC controller
* @param {FGmac} *instance_p, instance of FGmac controller
* @return err code information, FGMAC_SUCCESS indicates successothers indicates failed
*/
FError FGmacDeInitialize(FGmac *instance_p)
{
FASSERT(instance_p);
FError ret = FGMAC_SUCCESS;
instance_p->is_ready = 0;
memset(instance_p, 0, sizeof(*instance_p));
return ret;
}
/**
* @name: FGmacReset
* @msg: reset FGMAC controller
* @param {FGmac} *instance_p, instance of FGmac controller
* @return err code information, FGMAC_SUCCESS indicates successothers indicates failed
*/
static FError FGmacReset(FGmac *instance_p)
{
FASSERT(instance_p);
FGmacMacAddr mac_addr;
uintptr base_addr = instance_p->config.base_addr;
FError ret = FGMAC_SUCCESS;
u32 reg_val;
/* backup mac address before software reset */
memset(mac_addr, 0, sizeof(mac_addr));
FGmacGetMacAddr(base_addr, mac_addr);
/* disable all gmac & dma intr */
FGmacSetInterruptMask(instance_p, FGMAC_CTRL_INTR, FGMAC_ISR_MASK_ALL_BITS);
FGmacSetInterruptMask(instance_p, FGMAC_DMA_INTR, FGMAC_DMA_INTR_ENA_ALL_MASK);
/* stop gmac/dma tx and rx */
FGmacStop(instance_p);
/* do software reset per init */
ret = FGmacSoftwareReset(base_addr, FGMAC_RETRY_TIMES);
/* disable gmac & dma interrupts */
FGmacSetInterruptMask(instance_p, FGMAC_CTRL_INTR, FGMAC_ISR_MASK_ALL_BITS);
FGmacSetInterruptMask(instance_p, FGMAC_DMA_INTR, FGMAC_DMA_INTR_ENA_ALL_MASK);
/* recover mac address after softwate reset */
FGmacSetMacAddr(base_addr, mac_addr);
return ret;
}
/**
* @name: FGmacControllerSpeedConfig
* @msg: fgmac speed configuration
* @param {FGmac} *instance_p, instance of FGmac controller
* @param {u32} speed, speed value
* @return {*}
*/
void FGmacControllerSpeedConfig(FGmac *instance_p, u32 speed)
{
FASSERT(instance_p);
uintptr base_addr = instance_p->config.base_addr;
u32 reg_val = 0;
/* MAC配置寄存器 */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_CONF_OFFSET);
/* 设置通信速度FES=1000Mbps */
if (speed == FGMAC_PHY_SPEED_1000)
{
reg_val &= (~FGMAC_CONF_PORTSELECT);
reg_val &= (~FGMAC_CONF_FES);
}
/* 设置通信速度FES=100Mbps */
if (speed == FGMAC_PHY_SPEED_100)
{
reg_val |= FGMAC_CONF_PORTSELECT;
reg_val |= FGMAC_CONF_FES;
}
/* 设置通信速度FES=10Mbps */
if (speed == FGMAC_PHY_SPEED_10)
{
reg_val |= FGMAC_CONF_PORTSELECT;
reg_val &= (~FGMAC_CONF_FES);
}
FGMAC_WRITE_REG32(base_addr, FGMAC_CONF_OFFSET, reg_val);
}
/**
* @name: FGmacControllerDuplexConfig
* @msg: fgmac deplex mode configuration
* @param {FGmac} *instance_p, instance of FGmac controller
* @param {u32} duplex, duplex mode
* @return {*}
*/
void FGmacControllerDuplexConfig(FGmac *instance_p, u32 duplex)
{
FASSERT(instance_p);
uintptr base_addr = instance_p->config.base_addr;
u32 reg_val = 0;
/* MAC配置寄存器 */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_CONF_OFFSET);
/* 设置双工模式 */
if (duplex == FGMAC_PHY_MODE_FULLDUPLEX)
{
reg_val |= FGMAC_CONF_DUPLEX_MODE;
}
else
{
reg_val &= ~FGMAC_CONF_DUPLEX_MODE;
}
FGMAC_WRITE_REG32(base_addr, FGMAC_CONF_OFFSET, reg_val);
}
/**
* @name: FGmacControllerConfigure
* @msg: config FGMAC controller
* @param {FGmac} *instance_p, instance of FGmac controller
* @return err code information, FGMAC_SUCCESS indicates successothers indicates failed
*/
static FError FGmacControllerConfigure(FGmac *instance_p)
{
FASSERT(instance_p);
FGmacMacAddr mac_addr;
uintptr base_addr = instance_p->config.base_addr;
FError ret = FGMAC_SUCCESS;
u32 reg_val = 0;
/********gmac ctrl reg init*********/
/* Set the WD bit according to ETH Watchdog value */
/* Set the JD: bit according to ETH Jabber value */
/* Set the IFG bit according to ETH InterFrameGap value */
/* Set the DCRS bit according to ETH CarrierSense value */
/* Set the FES bit according to ETH Speed value */
/* Set the DO bit according to ETH ReceiveOwn value */
/* Set the LM bit according to ETH LoopbackMode value */
/* Set the DM bit according to ETH Mode value */
/* Set the IPCO bit according to ETH ChecksumOffload value */
/* Set the DR bit according to ETH RetryTransmission value */
/* Set the ACS bit according to ETH AutomaticPadCRCStrip value */
/* Set the BL bit according to ETH BackOffLimit value */
/* Set the DC bit according to ETH DeferralCheck value */
/* MAC配置寄存器 */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_CONF_OFFSET);
/* 使能载波侦听DCRS、失能环回模式LM */
reg_val &= ~(FGMAC_CONF_DCRS | FGMAC_CONF_LOOPBACK_MODE);
/* 设置帧内间隔IFG */
reg_val |= FGMAC_CONF_IFG(0);
/* 1000Mbps default */
reg_val &= (~FGMAC_CONF_PORTSELECT);
reg_val &= (~FGMAC_CONF_FES);
/* 双工模式 */
if (instance_p->config.duplex_mode)
{
reg_val |= FGMAC_CONF_DUPLEX_MODE;
}
else
{
reg_val &= ~FGMAC_CONF_DUPLEX_MODE;
}
/* 使能校验和卸载IPS */
if (FGMAC_CHECKSUM_BY_HARDWARE == instance_p->config.cheksum_mode)
{
reg_val |= FGMAC_CONF_IPC;
}
else
{
reg_val &= ~FGMAC_CONF_IPC;
}
/* 重发DR=1, 重发一次 */
reg_val |= FGMAC_CONF_DISABLE_RETRY;
/* 自动 PAD/ CRC 剥线, 全双工模式保留 */
reg_val |= FGMAC_CONF_ACS;
/* 后退限制, 全双工模式保留 */
reg_val |= FGMAC_CONF_BL(0);
/* 延期检查禁用 */
reg_val &= ~FGMAC_CONF_DC;
/* 使能类型帧的CRC剥离、禁用看门狗WD、禁用Jabber JD、帧突发启用BE、不能自接收DO(全双工保留)*/
reg_val |= (FGMAC_CONF_CST | FGMAC_CONF_WD | FGMAC_CONF_JD | FGMAC_CONF_BE | FGMAC_CONF_DO);
FGMAC_WRITE_REG32(base_addr, FGMAC_CONF_OFFSET, reg_val);
/********gmac filter reg init*********/
/* Set the RA bit according to ETH ReceiveAll value */
/* Set the SAF and SAIF bits according to ETH SourceAddrFilter value */
/* Set the PCF bit according to ETH PassControlFrames value */
/* Set the DBF bit according to ETH BroadcastFramesReception value */
/* Set the DAIF bit according to ETH DestinationAddrFilter value */
/* Set the PR bit according to ETH PromiscuousMode value */
/* Set the PM, HMC and HPF bits according to ETH MulticastFramesFilter value */
/* Set the HUC and HPF bits according to ETH UnicastFramesFilter value */
/* MAC帧过滤寄存器 */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_FRAME_FILTER_OFFSET);
/* 全部接收RA */
reg_val |= FGMAC_FRAME_FILTER_RA;
/* 通过控制帧PCF 10b */
reg_val |= FGMAC_FRAME_FILTER_PCF(2);
/* 失能禁用广播帧DBF */
reg_val &= ~FGMAC_FRAME_FILTER_DBF;
/* 失能通过所有多播PM */
reg_val &= ~FGMAC_FRAME_FILTER_PM;
/* 失能目的地址反向过滤DAIF */
reg_val &= ~FGMAC_FRAME_FILTER_DAIF;
/* 失能哈希单播PR */
reg_val &= ~FGMAC_FRAME_FILTER_PR;
FGMAC_WRITE_REG32(base_addr, FGMAC_FRAME_FILTER_OFFSET, reg_val);
/********hash reg*********/
FGMAC_WRITE_REG32(base_addr, FGMAC_HASH_HIGH_OFFSET, 0x0);
FGMAC_WRITE_REG32(base_addr, FGMAC_HASH_LOW_OFFSET, 0x0);
/********gmac flow ctrl reg init*********/
/* Set the PT bit according to ETH PauseTime value */
/* Set the DZPQ bit according to ETH ZeroQuantaPause value */
/* Set the PLT bit according to ETH PauseLowThreshold value */
/* Set the UP bit according to ETH UnicastPauseFrameDetect value */
/* Set the RFE bit according to ETH ReceiveFlowControl value */
/* Set the TFE bit according to ETH TransmitFlowControl value */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_FLOW_CTRL_OFFSET);
/* 禁用自动零暂停帧生成DZPQ */
reg_val |= FGMAC_FLOW_DZPQ;
/* 暂停低阈值PLT */
reg_val |= FGMAC_FLOW_PLT(0);
/* 禁用接收流控制RFE */
reg_val &= ~FGMAC_FLOW_RFE;
/* 禁用传输流控制TFE */
reg_val &= ~FGMAC_FLOW_TFE;
FGMAC_WRITE_REG32(base_addr, FGMAC_FLOW_CTRL_OFFSET, reg_val);
/********vlan tag reg*********/
/* Set the ETV bit according to ETH VLANTagComparison value */
/* Set the VL bit according to ETH VLANTagIdentifier value */
/* 接收帧的 VLAN 标记标识符 VL */
reg_val = FGMAC_VLAN_TAG_VL(0);
/* 设置VLAN 标记比较的位数ETV 1-12bit 0-16bit */
reg_val &= ~FGMAC_VLAN_TAG_ETV;
FGMAC_WRITE_REG32(base_addr, FGMAC_VLAN_TAG_OFFSET, reg_val);
return ret;
}
static FError FGmacDmaConfigure(FGmac *instance_p)
{
FASSERT(instance_p);
u32 reg_val;
FError ret = FGMAC_SUCCESS;
uintptr base_addr = instance_p->config.base_addr;
/********DMA总线模式寄存器*********/
/* Set the AAL bit according to ETH AddressAlignedBeats value */
/* Set the FB bit according to ETH FixedBurst value */
/* Set the RPBL and 4*PBL bits according to ETH RxDMABurstLength value */
/* Set the PBL and 4*PBL bits according to ETH TxDMABurstLength value */
/* Set the Enhanced DMA descriptors bit according to ETH EnhancedDescriptorFormat value*/
/* Set the DSL bit according to ETH DesciptorSkipLength value */
/* Set the PR and DA bits according to ETH DMAArbitration value */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_DMA_BUS_MODE_OFFSET);
reg_val |= FGMAC_DMA_BUS_AAL;
/* 使用单独的 PBL USP */
reg_val |= FGMAC_DMA_BUS_USP;
/* RxDMA PBL RPBL */
reg_val |= FGMAC_DMA_BUS_RPBL(32);
/* 固定突发 FB */
reg_val |= FGMAC_DMA_BUS_FB;
/* 控制 RxDMA 和 TxDMA 之间的加权循环仲裁中的优先级比率 PR */
reg_val |= FGMAC_DMA_BUS_PR(0);
/* 可编程突发长度 PBL */
reg_val |= FGMAC_DMA_BUS_PBL(32);
/* 交替描述表大小 ATDS */
reg_val |= FGMAC_DMA_BUS_ATDS;
FGMAC_WRITE_REG32(base_addr, FGMAC_DMA_BUS_MODE_OFFSET, reg_val);
/* dma set bus mode */
// FGMAC_WRITE_REG32(base_addr, FGMAC_DMA_BUS_MODE_OFFSET, FGMAC_DMA_BUS_INIT);
/********DMA操作模式寄存器*********/
/* Set the DT bit according to ETH DropTCPIPChecksumErrorFrame value */
/* Set the RSF bit according to ETH ReceiveStoreForward value */
/* Set the DFF bit according to ETH FlushReceivedFrame value */
/* Set the TSF bit according to ETH TransmitStoreForward value */
/* Set the TTC bit according to ETH TransmitThresholdControl value */
/* Set the FEF bit according to ETH ForwardErrorFrames value */
/* Set the FUF bit according to ETH ForwardUndersizedGoodFrames value */
/* Set the RTC bit according to ETH ReceiveThresholdControl value */
/* Set the OSF bit according to ETH SecondFrameOperate value */
reg_val = FGMAC_READ_REG32(base_addr, FGMAC_DMA_OP_OFFSET);
reg_val &= FGMAC_DMA_OP_CLEAR_MASK;
/* 丢弃 TCP / IP 校验和错误帧 DT */
reg_val &= ~FGMAC_DMA_OP_DT;
/* 接收存储转发 RSF */
reg_val |= FGMAC_DMA_OP_RSF;
/* 刷新正在接收的帧 DFF */
reg_val &= ~FGMAC_DMA_OP_DFF;
/* 发送存储和转发 TSF */
reg_val |= FGMAC_DMA_OP_TSF;
/* 传输阈值控制 TTC */
reg_val |= FGMAC_DMA_OP_TTC(7);
/* 在第二帧上操作 OSF */
reg_val |= FGMAC_DMA_OP_OSF;
FGMAC_WRITE_REG32(base_addr, FGMAC_DMA_OP_OFFSET, reg_val);
/* 刷新DMA发送FIFO FTF */
ret = FGmacFlushTxFifo(base_addr, FGMAC_RETRY_TIMES);
if (FGMAC_SUCCESS != ret)
{
FGMAC_ERROR("Gmac flush failed.");
}
/* AXI 突发长度 BLEN 16,8,4 */
reg_val = (FGMAC_DMA_AXI_BUS_MOD_BLEN16 | FGMAC_DMA_AXI_BUS_MOD_BLEN8 | FGMAC_DMA_AXI_BUS_MOD_BLEN4);
FGMAC_WRITE_REG32(base_addr, FGMAC_DMA_AXI_BUS_MOD_OFFSET, reg_val);
return ret;
}