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

875 lines
35 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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: fxmac.c
* Date: 2022-04-06 14:46:52
* LastEditTime: 2022-04-06 14:46:58
* Description:  This file is for
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#include "fxmac.h"
#include "ftypes.h"
#include "fxmac_hw.h"
#include "stdio.h"
#include "fdebug.h"
#define FXMAC_DEBUG_TAG "FXMAC"
#define FXMAC_PRINT_E(format, ...) FT_DEBUG_PRINT_E(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FXMAC_PRINT_I(format, ...) FT_DEBUG_PRINT_I(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FXMAC_PRINT_D(format, ...) FT_DEBUG_PRINT_D(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FXMAC_PRINT_W(format, ...) FT_DEBUG_PRINT_W(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
static void FXmacReset(FXmac *instance_p);
extern FError FXmacSetTypeIdCheck(FXmac *instance_p, u32 id_check, u8 index);
/**
* @name: FXmacSelectClk
* @msg: Determine the driver clock configuration based on the media independent interface
* @param {FXmac} *instance_p is a pointer to the instance to be worked on.
* @param {u32} speed interface speed
* @return {*}
*/
void FXmacSelectClk(FXmac *instance_p)
{
u32 reg_value;
s32 set_speed = 0;
u32 speed = instance_p->config.speed;
FASSERT(instance_p != NULL);
FASSERT((speed == FXMAC_SPEED_10) || (speed == FXMAC_SPEED_100) || (speed == FXMAC_SPEED_1000) || (speed == FXMAC_SPEED_2500) || (speed == FXMAC_SPEED_10000));
if ((instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_USXGMII) || (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_XGMII))
{
if (speed == FXMAC_SPEED_10000)
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x4);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
}
}
else if (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_SGMII)
{
FXMAC_PRINT_I("FXMAC_PHY_INTERFACE_MODE_SGMII init");
if (speed == FXMAC_SPEED_2500)
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x2);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3_0, 0x0); /*0x1c70*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL4_0, 0x0); /*0x1c74*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL3_0, 0x0); /*0x1c78*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL4_0, 0x0); /*0x1c7c*/
}
else if (speed == FXMAC_SPEED_1000)
{
FXMAC_PRINT_I("sgmii FXMAC_SPEED_1000 \r\n ");
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x4);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x8);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3_0, 0x0); /*0x1c70*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL4_0, 0x0); /*0x1c74*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL3_0, 0x0); /*0x1c78*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL4_0, 0x0); /*0x1c7c*/
}
else if ((speed == FXMAC_SPEED_100) || (speed == FXMAC_SPEED_10))
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x4);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x8);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x1);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x0);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3_0, 0x1); /*0x1c70*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL4_0, 0x0); /*0x1c74*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL3_0, 0x0); /*0x1c78*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL4_0, 0x1); /*0x1c7c*/
}
}
else if (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_RGMII)
{
FXMAC_PRINT_I("FXMAC_PHY_INTERFACE_MODE_RGMII init");
if (speed == FXMAC_SPEED_1000)
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_MII_SELECT, 0x1); /*0x1c18*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SEL_MII_ON_RGMII, 0x0); /*0x1c1c*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0); /*0x1c20*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1); /*0x1c24*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0); /*0x1c28*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x0); /*0x1c2c*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x0); /*0x1c30*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x1); /*0x1c34*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_CLK_250M_DIV10_DIV100_SEL,
0x0); /*0x1c38*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1); /*0x1c48*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL0, 0x1); /*0x1c80*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL1, 0x0); /*0x1c84*/
}
else if (speed == FXMAC_SPEED_100)
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SEL_MII_ON_RGMII, 0x0); /*0x1c1c*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0); /*0x1c20*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1); /*0x1c24*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0); /*0x1c28*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x0); /*0x1c2c*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x0); /*0x1c30*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x1); /*0x1c34*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_CLK_250M_DIV10_DIV100_SEL,
0x0); /*0x1c38*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1); /*0x1c48*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL0, 0x0); /*0x1c80*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL1, 0x0); /*0x1c84*/
}
else
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SEL_MII_ON_RGMII, 0x0); /*0x1c1c*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0); /*0x1c20*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1); /*0x1c24*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0); /*0x1c28*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x0); /*0x1c2c*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x0); /*0x1c30*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x1); /*0x1c34*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_CLK_250M_DIV10_DIV100_SEL,
0x1); /*0x1c38*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1); /*0x1c48*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL0, 0x0); /*0x1c80*/
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL1, 0x0); /*0x1c84*/
}
}
else if (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_RMII)
{
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1); /*0x1c48*/
}
switch (speed)
{
case FXMAC_SPEED_25000:
set_speed = 2;
break;
case FXMAC_SPEED_10000:
set_speed = 4;
break;
case FXMAC_SPEED_5000:
set_speed = 3;
break;
case FXMAC_SPEED_2500:
set_speed = 2;
break;
case FXMAC_SPEED_1000:
set_speed = 1;
break;
default:
set_speed = 0;
break;
}
/*GEM_HSMAC(0x0050) provide rate to the external*/
reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_HSMAC);
reg_value &= ~FXMAC_GEM_HSMACSPEED_MASK;
reg_value |= (set_speed) &FXMAC_GEM_HSMACSPEED_MASK;
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_HSMAC, reg_value);
reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_HSMAC);
FXMAC_PRINT_I("FXMAC_GEM_HSMAC is %x \r\n ", reg_value);
}
/**
* Start the Ethernet controller as follows:
* - Enable transmitter if FXMAC_TRANSMIT_ENABLE_OPTION is set
* - Enable receiver if FXMAC_RECEIVER_ENABLE_OPTION is set
* - Start the SG DMA send and receive channels and enable the device
* interrupt
*
* @param instance_p is a pointer to the instance to be worked on.
*
* @return N/A
*
* @note
* Hardware is configured with scatter-gather DMA, the driver expects to start
* the scatter-gather channels and expects that the user has previously set up
* the buffer descriptor lists.
*
* This function makes use of internal resources that are shared between the
* Start, Stop, and Set/ClearOptions functions. So if one task might be setting
* device options while another is trying to start the device, the user is
* required to provide protection of this shared data (typically using a
* semaphore).
*
* This function must not be preempted by an interrupt that may service the
* device.
*
*/
void FXmacStart(FXmac *instance_p)
{
u32 reg_val;
u32 reg = 0;
/* Assert bad arguments and conditions */
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);
/* Start DMA */
/* When starting the DMA channels, both transmit and receive sides
* need an initialized BD list.
*/
FASSERT(instance_p->rx_bd_queue.bdring.base_bd_addr != 0);
reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_RXQBASE_OFFSET);
reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_TXQBASE_OFFSET);
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_RXQBASE_OFFSET,
instance_p->rx_bd_queue.bdring.base_bd_addr);
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_TXQBASE_OFFSET,
instance_p->tx_bd_queue.bdring.base_bd_addr);
reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_RXQBASE_OFFSET);
reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_TXQBASE_OFFSET);
/* clear any existed int status */
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_ISR_OFFSET,
FXMAC_IXR_ALL_MASK);
/* Enable transmitter if not already enabled */
if ((instance_p->config.network_default_config & (u32)FXMAC_TRANSMITTER_ENABLE_OPTION) != 0x00000000U)
{
reg_val = FXMAC_READREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET);
if ((!(reg_val & FXMAC_NWCTRL_TXEN_MASK)) == TRUE)
{
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET,
reg_val | (u32)FXMAC_NWCTRL_TXEN_MASK);
}
}
/* Enable receiver if not already enabled */
if ((instance_p->config.network_default_config & FXMAC_RECEIVER_ENABLE_OPTION) != 0x00000000U)
{
reg_val = FXMAC_READREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET);
FXMAC_PRINT_I("endable receiver 0x%x \r\n ", reg_val);
if ((!(reg_val & FXMAC_NWCTRL_RXEN_MASK)) == TRUE)
{
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET,
reg_val | (u32)FXMAC_NWCTRL_RXEN_MASK);
}
}
FXMAC_PRINT_I("FXMAC_NWCTRL_OFFSET is 0x%x \r\n", FXMAC_READREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET));
/* Enable TX and RX interrupt */
FXMAC_INT_ENABLE(instance_p, FXMAC_IXR_LINKCHANGE_MASK | FXMAC_IXR_TX_ERR_MASK | FXMAC_IXR_RX_ERR_MASK | FXMAC_IXR_RXCOMPL_MASK | FXMAC_IXR_TXCOMPL_MASK);
/* Mark as started */
instance_p->is_started = FT_COMPONENT_IS_STARTED;
return;
}
/**
* Gracefully stop the Ethernet MAC as follows:
* - Disable all interrupts from this device
* - Stop DMA channels
* - Disable the tansmitter and receiver
*
* Device options currently in effect are not changed.
*
* This function will disable all interrupts. Default interrupts settings that
* had been enabled will be restored when FXmacStart() is called.
*
* @param instance_p is a pointer to the instance to be worked on.
*
* @note
* This function makes use of internal resources that are shared between the
* Start, Stop, Setoptions, and Clearoptions functions. So if one task might be
* setting device options while another is trying to start the device, the user
* is required to provide protection of this shared data (typically using a
* semaphore).
*
* Stopping the DMA channels causes this function to block until the DMA
* operation is complete.
*
*/
void FXmacStop(FXmac *instance_p)
{
u32 reg_val;
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);
/* Disable all interrupts */
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_IDR_OFFSET,
FXMAC_IXR_ALL_MASK);
/* Disable the receiver & transmitter */
reg_val = FXMAC_READREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET);
reg_val &= (u32)(~FXMAC_NWCTRL_RXEN_MASK);
reg_val &= (u32)(~FXMAC_NWCTRL_TXEN_MASK);
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET, reg_val);
/* Mark as stopped */
instance_p->is_started = 0U;
}
static u32 FXmacClkDivGet(FXmac *instance_p)
{
FXmacConfig *config_p;
config_p = &instance_p->config;
if (config_p->pclk_hz <= 20000000)
{
return FXMAC_NWCFG_CLOCK_DIV8_MASK;
}
else if (config_p->pclk_hz <= 40000000)
{
return FXMAC_NWCFG_CLOCK_DIV16_MASK;
}
else if (config_p->pclk_hz <= 80000000)
{
return FXMAC_NWCFG_CLOCK_DIV32_MASK;
}
else if (instance_p->moudle_id >= 2)
{
if (config_p->pclk_hz <= 120000000)
{
return FXMAC_NWCFG_CLOCK_DIV48_MASK;
}
else if (config_p->pclk_hz <= 160000000)
{
return FXMAC_NWCFG_CLOCK_DIV64_MASK;
}
else if (config_p->pclk_hz <= 240000000)
{
return FXMAC_NWCFG_CLOCK_DIV96_MASK;
}
else if (config_p->pclk_hz <= 320000000)
{
return FXMAC_NWCFG_CLOCK_DIV128_MASK;
}
else
{
return FXMAC_NWCFG_CLOCK_DIV224_MASK;
}
}
else
{
return FXMAC_NWCFG_CLOCK_DIV64_MASK;
}
}
static u32 FXmacDmaWidth(FXmac *instance_p)
{
u32 read_regs = 0;
FXmacConfig *config_p;
config_p = &instance_p->config;
if (instance_p->moudle_id < 2)
{
return FXMAC_NWCFG_BUS_WIDTH_32_MASK;
}
read_regs = FXMAC_READREG32(config_p->base_address, FXMAC_DESIGNCFG_DEBUG1_OFFSET);
switch ((read_regs & FXMAC_DESIGNCFG_DEBUG1_BUS_WIDTH_MASK) >> 25)
{
case 4:
FXMAC_PRINT_I("bus width is 128");
return FXMAC_NWCFG_BUS_WIDTH_128_MASK;
case 2:
FXMAC_PRINT_I("bus width is 64");
return FXMAC_NWCFG_BUS_WIDTH_64_MASK;
default:
FXMAC_PRINT_I("bus width is 32");
return FXMAC_NWCFG_BUS_WIDTH_32_MASK;
}
}
static void FXmacDmaReset(FXmac *instance_p)
{
u32 queue = 0;
FXmacConfig *config_p;
config_p = &instance_p->config;
u32 dmacfg = 0;
u32 rx_buf_size = 0;
rx_buf_size = instance_p->max_frame_size / FXMAC_RX_BUF_UNIT;
rx_buf_size += ((instance_p->max_frame_size % FXMAC_RX_BUF_UNIT) != 0) ? 1 : 0; /* roundup */
if (instance_p->moudle_id >= 2)
{
for (queue = 0; queue < config_p->max_queue_num; queue++)
{
dmacfg = 0;
FXmacSetQueuePtr(instance_p, (uintptr)NULL, queue, (u16)FXMAC_SEND);
FXmacSetQueuePtr(instance_p, (uintptr)NULL, queue, (u16)FXMAC_RECV);
if (queue)
{
FXMAC_WRITEREG32(config_p->base_address, FXMAC_RXBUFQX_SIZE_OFFSET(queue), rx_buf_size);
}
else /* queue is 0 */
{
dmacfg |= ((u32)FXMAC_DMACR_RXBUF_MASK & (rx_buf_size << FXMAC_DMACR_RXBUF_SHIFT));
}
}
dmacfg |= (config_p->dma_brust_length & FXMAC_DMACR_BLENGTH_MASK);
dmacfg &= ~FXMAC_DMACR_ENDIAN_MASK;
dmacfg &= ~FXMAC_DMACR_SWAP_MANAGEMENT_MASK; /* 选择小端 */
dmacfg &= ~FXMAC_DMACR_TCPCKSUM_MASK; /* close transmitter checksum generation engine */
dmacfg &= ~FXMAC_DMACR_ADDR_WIDTH_64;
dmacfg |= FXMAC_DMACR_RXSIZE_MASK | FXMAC_DMACR_TXSIZE_MASK;
#if defined(__aarch64__) || defined(__arch64__)
dmacfg |= FXMAC_DMACR_ADDR_WIDTH_64;
#endif
}
else
{
FXmacSetQueuePtr(instance_p, (uintptr)NULL, 0, (u16)FXMAC_SEND);
FXmacSetQueuePtr(instance_p, (uintptr)NULL, 0, (u16)FXMAC_RECV);
dmacfg |= ((u32)FXMAC_DMACR_RXBUF_MASK & (rx_buf_size << FXMAC_DMACR_RXBUF_SHIFT));
dmacfg |= (config_p->dma_brust_length & FXMAC_DMACR_BLENGTH_MASK);
dmacfg &= ~FXMAC_DMACR_ENDIAN_MASK;
dmacfg &= ~FXMAC_DMACR_SWAP_MANAGEMENT_MASK; /* 选择小端 */
dmacfg &= ~FXMAC_DMACR_TCPCKSUM_MASK; /* close transmitter checksum generation engine */
dmacfg &= ~FXMAC_DMACR_ADDR_WIDTH_64;
dmacfg |= FXMAC_DMACR_RXSIZE_MASK | FXMAC_DMACR_TXSIZE_MASK;
#if defined(__aarch64__) || defined(__arch64__)
dmacfg |= FXMAC_DMACR_ADDR_WIDTH_64;
#endif
}
FXMAC_WRITEREG32(config_p->base_address, FXMAC_DMACR_OFFSET, dmacfg);
}
/**
* Perform a graceful reset of the Ethernet MAC. Resets the DMA channels, the
* transmitter, and the receiver.
*
* Steps to reset
* - Stops transmit and receive channels
* - Stops DMA
* - Configure transmit and receive buffer size to default
* - Clear transmit and receive status register and counters
* - Clear all interrupt sources
* - Clear phy (if there is any previously detected) address
* - Clear MAC addresses (1-4) as well as Type IDs and hash value
*
* All options are placed in their default state. Any frames in the
* descriptor lists will remain in the lists. The side effect of doing
* this is that after a reset and following a restart of the device, frames
* were in the list before the reset may be transmitted or received.
*
* The upper layer software is responsible for re-configuring (if necessary)
* and restarting the MAC after the reset. Note also that driver statistics
* are not cleared on reset. It is up to the upper layer software to clear the
* statistics if needed.
*
* When a reset is required, the driver notifies the upper layer software of
* this need through the ErrorHandler callback and specific status codes.
* The upper layer software is responsible for calling this Reset function
* and then re-configuring the device.
*
* @param instance_p is a pointer to the instance to be worked on.
*
*/
static void FXmacReset(FXmac *instance_p)
{
u32 reg_val, write_reg = 0;
u8 i;
s8 mac_addr[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
u32 rx_buf_num;
FASSERT(instance_p != NULL);
/* Stop the device and reset hardware */
FXmacStop(instance_p);
instance_p->moudle_id = (FXMAC_READREG32(instance_p->config.base_address, FXMAC_REVISION_REG_OFFSET) & FXMAC_IDENTIFICATION_MASK) >> 16;
FXMAC_PRINT_I("instance_p->moudle_id is %d \r\n", instance_p->moudle_id);
instance_p->max_mtu_size = FXMAC_MTU;
instance_p->max_frame_size = FXMAC_MTU + FXMAC_HDR_SIZE + FXMAC_TRL_SIZE;
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_NWCTRL_OFFSET,
((FXMAC_NWCTRL_STATCLR_MASK) & (u32)(~FXMAC_NWCTRL_LOOPEN_MASK)) | FXMAC_NWCTRL_MDEN_MASK);
write_reg = FXmacClkDivGet(instance_p); /* mdio clock division */
write_reg |= FXmacDmaWidth(instance_p); /* 位宽 */
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_NWCFG_OFFSET, write_reg);
FXmacDmaReset(instance_p);
/* This register, when read provides details of the status of the receive path. */
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_RXSR_OFFSET, FXMAC_SR_ALL_MASK);
/* write 1 ro the relavant bit location disable that particular interrupt */
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_IDR_OFFSET, FXMAC_IXR_ALL_MASK);
reg_val = FXMAC_READREG32(instance_p->config.base_address,
FXMAC_ISR_OFFSET);
FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_ISR_OFFSET,
reg_val);
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_TXSR_OFFSET, FXMAC_SR_ALL_MASK);
FXmacClearHash(instance_p);
/* set default mac address */
for (i = 0U; i < 4U; i++)
{
(void)FXmacSetMacAddress(instance_p, mac_addr, i);
(void)FXmacGetMacAddress(instance_p, mac_addr, i);
(void)FXmacSetTypeIdCheck(instance_p, 0x00000000U, i);
}
/* clear all counters */
for (i = 0U; i < (u8)((FXMAC_LAST_OFFSET - FXMAC_OCTTXL_OFFSET) / 4U);
i++)
{
(void)FXMAC_READREG32(instance_p->config.base_address,
FXMAC_OCTTXL_OFFSET + (u32)(((u32)i) * ((u32)4)));
}
/* Sync default options with hardware but leave receiver and
* transmitter disabled. They get enabled with FXmacStart() if
* FXMAC_TRANSMITTER_ENABLE_OPTION and
* FXMAC_RECEIVER_ENABLE_OPTION are set.
*/
FXmacSetOptions(instance_p, instance_p->config.network_default_config & ~((u32)FXMAC_TRANSMITTER_ENABLE_OPTION | (u32)FXMAC_RECEIVER_ENABLE_OPTION), 0);
FXmacClearOptions(instance_p, ~instance_p->config.network_default_config, 0);
}
/**
* @name: FXmacInitInterface
* @msg: Initialize the MAC controller configuration based on the PHY interface type
* @note:
* @param {FXmac} *instance_p is a pointer to the instance to be worked on.
*/
void FXmacInitInterface(FXmac *instance_p)
{
u32 config, control;
FXmacConfig *config_p;
config_p = &instance_p->config;
if (config_p->interface == FXMAC_PHY_INTERFACE_MODE_XGMII)
{
config = FXMAC_READREG32(config_p->base_address, FXMAC_NWCFG_OFFSET);
config &= ~FXMAC_NWCFG_PCSSEL_MASK;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCFG_OFFSET, config);
control = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET);
control |= FXMAC_NWCTRL_ENABLE_HS_MAC_MASK; /* Use high speed MAC */
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, control);
config_p->duplex = 1;
}
else if (config_p->interface == FXMAC_PHY_INTERFACE_MODE_USXGMII)
{
config = FXMAC_READREG32(config_p->base_address, FXMAC_NWCFG_OFFSET);
config |= FXMAC_NWCFG_PCSSEL_MASK;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCFG_OFFSET, config);
control = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET);
control |= FXMAC_NWCTRL_ENABLE_HS_MAC_MASK; /* Use high speed MAC */
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, control);
control = FXMAC_READREG32(config_p->base_address, FXMAC_GEM_USX_CONTROL_OFFSET);
control &= ~(FXMAC_GEM_USX_TX_SCR_BYPASS | FXMAC_GEM_USX_RX_SCR_BYPASS);
control |= FXMAC_GEM_USX_RX_SYNC_RESET;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_GEM_USX_CONTROL_OFFSET, control);
control = FXMAC_READREG32(config_p->base_address, FXMAC_GEM_USX_CONTROL_OFFSET);
control &= ~FXMAC_GEM_USX_RX_SYNC_RESET;
control |= FXMAC_GEM_USX_TX_DATAPATH_EN;
control |= FXMAC_GEM_USX_SIGNAL_OK;
if (config_p->speed == FXMAC_SPEED_10000)
{
control |= FXMAC_GEM_USX_HS_MAC_SPEED_10G;
}
else if (config_p->speed == FXMAC_SPEED_25000)
{
control |= FXMAC_GEM_USX_HS_MAC_SPEED_2_5G;
}
else if (config_p->speed == FXMAC_SPEED_1000)
{
control |= FXMAC_GEM_USX_HS_MAC_SPEED_1G;
}
else if (config_p->speed == FXMAC_SPEED_100)
{
control |= FXMAC_GEM_USX_HS_MAC_SPEED_100M;
}
FXMAC_WRITEREG32(config_p->base_address, FXMAC_GEM_USX_CONTROL_OFFSET, control);
config_p->duplex = 1;
}
else if (config_p->interface == FXMAC_PHY_INTERFACE_MODE_SGMII)
{
config = FXMAC_READREG32(config_p->base_address, FXMAC_NWCFG_OFFSET);
config |= FXMAC_NWCFG_PCSSEL_MASK | FXMAC_NWCFG_SGMII_MODE_ENABLE_MASK;
config &= ~(FXMAC_NWCFG_100_MASK | FXMAC_NWCFG_FDEN_MASK);
if (instance_p->moudle_id >= 2)
{
config &= ~FXMAC_NWCFG_1000_MASK;
}
if (config_p->duplex)
{
config |= FXMAC_NWCFG_FDEN_MASK;
}
if (config_p->speed == FXMAC_SPEED_100)
{
config |= FXMAC_NWCFG_100_MASK;
}
else if (config_p->speed == FXMAC_SPEED_1000)
{
config |= FXMAC_NWCFG_1000_MASK;
}
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCFG_OFFSET, config);
if (config_p->speed == FXMAC_SPEED_2500)
{
control = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET);
control |= FXMAC_NWCTRL_TWO_PT_FIVE_GIG_MASK;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, control);
}
else
{
control = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET);
control &= ~FXMAC_NWCTRL_TWO_PT_FIVE_GIG_MASK;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, control);
}
control = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET);
control &= ~FXMAC_NWCTRL_ENABLE_HS_MAC_MASK;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, control);
control = FXMAC_READREG32(config_p->base_address, FXMAC_PCS_CONTROL_OFFSET);
control |= FXMAC_PCS_CONTROL_ENABLE_AUTO_NEG;
FXMAC_WRITEREG32(config_p->base_address, FXMAC_PCS_CONTROL_OFFSET, control);
}
else
{
config = FXMAC_READREG32(config_p->base_address, FXMAC_NWCFG_OFFSET);
FXMAC_PRINT_I("select rgmii \r\n");
config &= ~FXMAC_NWCFG_PCSSEL_MASK;
config &= ~(FXMAC_NWCFG_100_MASK | FXMAC_NWCFG_FDEN_MASK);
if (instance_p->moudle_id >= 2)
{
config &= ~FXMAC_NWCFG_1000_MASK;
}
if (config_p->duplex)
{
config |= FXMAC_NWCFG_FDEN_MASK;
}
if (config_p->speed == FXMAC_SPEED_100)
{
config |= FXMAC_NWCFG_100_MASK;
}
else if (config_p->speed == FXMAC_SPEED_1000)
{
config |= FXMAC_NWCFG_1000_MASK;
}
if (config_p->duplex)
{
config |= FXMAC_NWCFG_FDEN_MASK;
}
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCFG_OFFSET, config);
control = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET);
control &= ~FXMAC_NWCTRL_ENABLE_HS_MAC_MASK; /* Use high speed MAC */
FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, control);
}
}
static void FXmacIrqStubHandler(void)
{
FASSERT_MSG(0, "Please register the interrupt callback function");
}
/**
* @name: FXmacCfgInitialize
* @msg: Initialize a specific fxmac instance/driver.
* @note:
* @param {FXmac} *instance_p is a pointer to the instance to be worked on.
* @param {FXmacConfig} *config_p is the device configuration structure containing required
* hardware build data.
* @return {FT_SUCCESS} if initialization was successful
*/
FError FXmacCfgInitialize(FXmac *instance_p, const FXmacConfig *config_p)
{
/* Verify arguments */
FASSERT(instance_p != NULL);
FASSERT(config_p != NULL);
instance_p->config = *config_p;
instance_p->link_status = FXMAC_LINKDOWN;
/* Reset the hardware and set default options */
instance_p->is_ready = FT_COMPONENT_IS_READY;
FXmacReset(instance_p);
instance_p->send_irq_handler = (FXmacIrqHandler)FXmacIrqStubHandler;
instance_p->send_args = NULL;
instance_p->recv_irq_handler = (FXmacIrqHandler)FXmacIrqStubHandler;
instance_p->recv_args = NULL;
instance_p->error_irq_handler = (FXmacErrorIrqHandler)FXmacIrqStubHandler;
instance_p->error_args = NULL;
instance_p->link_change_handler = (FXmacIrqHandler)FXmacIrqStubHandler;
instance_p->link_change_args = NULL;
instance_p->restart_handler = (FXmacIrqHandler)FXmacIrqStubHandler;
instance_p->restart_args = NULL;
return FT_SUCCESS;
}
/**
* This function sets the start address of the transmit/receive buffer queue.
*
* @param instance_p is a pointer to the instance to be worked on.
* @param queue_p is the address of the Queue to be written
* @param queue_num is the Buffer Queue Index
* @param direction indicates Transmit/Receive
*
* @note
* The buffer queue addresses has to be set before starting the transfer, so
* this function has to be called in prior to FXmacStart()
*
*/
void FXmacSetQueuePtr(FXmac *instance_p, uintptr queue_p, u8 queue_num,
u32 direction)
{
/* Assert bad arguments and conditions */
FASSERT(instance_p != NULL);
FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);
/* If already started, then there is nothing to do */
if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED)
{
return;
}
if (queue_num == 0x00U)
{
if (direction == FXMAC_SEND)
{
/* set base start address of TX buffer queue (tx buffer descriptor list) */
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_TXQBASE_OFFSET,
(queue_p & ULONG64_LO_MASK) | (((queue_p == (uintptr)0)) ? 1 : 0));
}
else
{
/* set base start address of RX buffer queue (rx buffer descriptor list) */
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_RXQBASE_OFFSET,
(queue_p & ULONG64_LO_MASK) | (((queue_p == (uintptr)0)) ? 1 : 0));
}
}
else
{
if (direction == FXMAC_SEND)
{
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_QUEUE_REGISTER_OFFSET(FXMAC_TXQ1BASE_OFFSET, queue_num),
(queue_p & ULONG64_LO_MASK) | (((queue_p == (uintptr)0)) ? 1 : 0));
}
else
{
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_QUEUE_REGISTER_OFFSET(FXMAC_TXQ1BASE_OFFSET, queue_num),
(queue_p & ULONG64_LO_MASK) | (((queue_p == (uintptr)0)) ? 1 : 0));
}
}
#ifdef __aarch64__
if (direction == FXMAC_SEND)
{
/* Set the MSB of TX Queue start address */
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_MSBBUF_TXQBASE_OFFSET,
(u32)((queue_p & ULONG64_HI_MASK) >> 32U));
}
else
{
/* Set the MSB of RX Queue start address */
FXMAC_WRITEREG32(instance_p->config.base_address,
FXMAC_MSBBUF_RXQBASE_OFFSET,
(u32)((queue_p & ULONG64_HI_MASK) >> 32U));
}
#endif
}