mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-24 07:18:54 +00:00
1283 lines
37 KiB
C
1283 lines
37 KiB
C
/*
|
|
* Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "lwip/opt.h"
|
|
#include "lwip/def.h"
|
|
#include "lwip/mem.h"
|
|
#include "lwip/pbuf.h"
|
|
#include "lwip/timeouts.h"
|
|
#include "netif/etharp.h"
|
|
#include "lwip/err.h"
|
|
#include <string.h>
|
|
#include <rtconfig.h>
|
|
#include <aic_core.h>
|
|
#include "aic_mac.h"
|
|
#include "aic_phy.h"
|
|
#include <aic_hal.h>
|
|
|
|
#define USE_FULL_ASSERT
|
|
#ifdef USE_FULL_ASSERT
|
|
#define assert_param(expr) \
|
|
((expr) ? \
|
|
(void)0 : \
|
|
assert_failed((uint8_t *)__FILE__, (uint8_t *)__func__, __LINE__))
|
|
|
|
static inline void assert_failed(uint8_t *file, uint8_t *func, uint32_t line)
|
|
{
|
|
printf("Wrong parameters value: file %s function %s on line %d\r\n", file,
|
|
func, (unsigned int)line);
|
|
|
|
/* Infinite loop */
|
|
while (1) {
|
|
}
|
|
}
|
|
#else
|
|
#define assert_param(expr) ((void)0)
|
|
#endif
|
|
|
|
#if MAX_ETH_MAC_PORT == 2
|
|
unsigned long mac_base[MAX_ETH_MAC_PORT] = { GMAC0_BASE, GMAC1_BASE };
|
|
unsigned long mac_irq[MAX_ETH_MAC_PORT] = { GMAC0_IRQn, GMAC0_IRQn+1 };
|
|
#else
|
|
unsigned long mac_base[MAX_ETH_MAC_PORT] = { GMAC0_BASE };
|
|
unsigned long mac_irq[MAX_ETH_MAC_PORT] = { GMAC0_IRQn };
|
|
#endif
|
|
|
|
#ifdef CONFIG_MAC_USE_UNCACHE_BUF
|
|
CMA_DATA_DEFINE aicmac_dma_desc_ctl_t dctl[MAX_ETH_MAC_PORT];
|
|
#else
|
|
aicmac_dma_desc_ctl_t dctl[MAX_ETH_MAC_PORT];
|
|
#endif
|
|
|
|
aicmac_config_t mac_config[MAX_ETH_MAC_PORT] = {
|
|
/* mac port 0: 100M/1000M */
|
|
{
|
|
.port = 0,
|
|
#ifdef AIC_DEV_GMAC0_PHYADDR
|
|
.phyaddr = AIC_DEV_GMAC0_PHYADDR,
|
|
#else
|
|
.phyaddr = 1,
|
|
#endif
|
|
#ifdef AIC_DEV_GMAC0_RMII
|
|
.rgmii_bus = 0,
|
|
.max_speed = SPEED_100,
|
|
#else
|
|
.rgmii_bus = 1,
|
|
.max_speed = SPEED_1000,
|
|
#endif
|
|
.duplex = 1,
|
|
.flowctl = 1,
|
|
.autonegotiation = 1,
|
|
#ifdef LPKG_LWIP_USING_TX_HW_CHECKSUM
|
|
.coe_tx = 1,
|
|
#else
|
|
.coe_tx = 0,
|
|
#endif
|
|
#ifdef LPKG_LWIP_USING_RX_HW_CHECKSUM
|
|
.coe_rx = 1,
|
|
#else
|
|
.coe_rx = 0,
|
|
#endif
|
|
.dma_rxpbl = CONFIG_DMA_RX_PBL,
|
|
.dma_txpbl = CONFIG_DMA_TX_PBL,
|
|
.dma_pblx8 = 1,
|
|
.dma_fixed_burst = 1,
|
|
.dma_mixed_burst = 0,
|
|
.dma_aal = 1,
|
|
.dma_sf_mode = 1,
|
|
#ifdef AIC_DEV_GMAC0_PHYRST_GPIO
|
|
.phyrst_gpio_name = AIC_DEV_GMAC0_PHYRST_GPIO,
|
|
#endif
|
|
},
|
|
|
|
#if MAX_ETH_MAC_PORT == 2
|
|
/* mac port 1: 100M/1000M */
|
|
{
|
|
.port = 1,
|
|
#ifdef AIC_DEV_GMAC1_PHYADDR
|
|
.phyaddr = AIC_DEV_GMAC1_PHYADDR,
|
|
#else
|
|
.phyaddr = 1,
|
|
#endif
|
|
#ifdef AIC_DEV_GMAC1_RMII
|
|
.rgmii_bus = 0,
|
|
.max_speed = SPEED_100,
|
|
#else
|
|
.rgmii_bus = 1,
|
|
.max_speed = SPEED_1000,
|
|
#endif
|
|
.duplex = 1,
|
|
.flowctl = 1,
|
|
.autonegotiation = 1,
|
|
#ifdef LPKG_LWIP_USING_TX_HW_CHECKSUM
|
|
.coe_tx = 1,
|
|
#else
|
|
.coe_tx = 0,
|
|
#endif
|
|
#ifdef LPKG_LWIP_USING_RX_HW_CHECKSUM
|
|
.coe_rx = 1,
|
|
#else
|
|
.coe_rx = 0,
|
|
#endif
|
|
.dma_rxpbl = CONFIG_DMA_RX_PBL,
|
|
.dma_txpbl = CONFIG_DMA_TX_PBL,
|
|
.dma_pblx8 = 1,
|
|
.dma_fixed_burst = 1,
|
|
.dma_mixed_burst = 0,
|
|
.dma_aal = 1,
|
|
.dma_sf_mode = 1,
|
|
#ifdef AIC_DEV_GMAC1_PHYRST_GPIO
|
|
.phyrst_gpio_name = AIC_DEV_GMAC1_PHYRST_GPIO,
|
|
#endif
|
|
},
|
|
#endif
|
|
};
|
|
|
|
extern void aicmac_low_level_init(uint32_t port, bool en);
|
|
|
|
void aicmac_exit(uint32_t port)
|
|
{
|
|
/* Check the parameters */
|
|
assert_param(port < MAX_ETH_MAC_PORT);
|
|
|
|
/* HW Low-Level Init */
|
|
aicmac_low_level_init(port, DISABLE);
|
|
}
|
|
|
|
int aicmac_init(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
uint32_t ahbclk = 0;
|
|
uint32_t pin = 0;
|
|
uint32_t p = 0;
|
|
uint32_t g = 0;
|
|
|
|
/* Check the parameters */
|
|
assert_param(port < MAX_ETH_MAC_PORT);
|
|
|
|
memset(&dctl[port], 0, sizeof(dctl[0]));
|
|
|
|
/* HW Low-Level Init */
|
|
aicmac_low_level_init(port, ENABLE);
|
|
|
|
/* Software reset */
|
|
aicmac_sw_reset(port);
|
|
/* Wait for software reset */
|
|
while (aicmac_get_sw_reset_status(port) == SET) {
|
|
|
|
}
|
|
|
|
/* phy reset must after mac reset */
|
|
if (mac_config[port].phyrst_gpio_name) {
|
|
pin = hal_gpio_name2pin(mac_config[port].phyrst_gpio_name);
|
|
g = GPIO_GROUP(pin);
|
|
p = GPIO_GROUP_PIN(pin);
|
|
|
|
hal_gpio_direction_output(g, p);
|
|
|
|
hal_gpio_clr_output(g, p);
|
|
aicos_mdelay(50);
|
|
hal_gpio_set_output(g, p);
|
|
aicos_mdelay(50);
|
|
}
|
|
|
|
aicos_udelay(1000);
|
|
|
|
/* MDCIO Internal Clock Select */
|
|
tmpreg = readl(MAC(port, mdioctl));
|
|
tmpreg &= ~(ETH_MDIOCTL_CR_MSK);
|
|
ahbclk = hal_clk_get_freq(CLK_AHB0);
|
|
if ((ahbclk >= 20000000) && (ahbclk < 35000000)) {
|
|
tmpreg |= ETH_MDIOCTL_CR_Div16;
|
|
} else if ((ahbclk >= 35000000) && (ahbclk < 60000000)) {
|
|
tmpreg |= ETH_MDIOCTL_CR_Div26;
|
|
} else if ((ahbclk >= 60000000) && (ahbclk < 100000000)) {
|
|
tmpreg |= ETH_MDIOCTL_CR_Div42;
|
|
} else if ((ahbclk >= 100000000) && (ahbclk < 150000000)) {
|
|
tmpreg |= ETH_MDIOCTL_CR_Div62;
|
|
} else if ((ahbclk >= 150000000) && (ahbclk < 250000000)) {
|
|
tmpreg |= ETH_MDIOCTL_CR_Div102;
|
|
} else {
|
|
/* ((ahbclk >= 250000000)&&(ahbclk <= 300000000)) */
|
|
tmpreg |= ETH_MDIOCTL_CR_Div124;
|
|
}
|
|
writel(tmpreg, MAC(port, mdioctl));
|
|
|
|
/*------------------------ MAC Configuration --------------------*/
|
|
/* (1) macconf */
|
|
tmpreg = readl(MAC(port, macconf));
|
|
tmpreg &= ~ETH_MACCONF_SPEED_MSK;
|
|
if (mac_config[port].max_speed == SPEED_100) {
|
|
tmpreg |= ETH_MACCONF_SPEED_100M;
|
|
/* set syscfg RMII */
|
|
} else if (mac_config[port].max_speed == SPEED_1000) {
|
|
tmpreg |= ETH_MACCONF_SPEED_1000M;
|
|
/* set syscfg RGMII */
|
|
}
|
|
|
|
if (mac_config[port].duplex)
|
|
tmpreg |= ETH_MACCONF_DM;
|
|
else
|
|
tmpreg &= ~ETH_MACCONF_DM;
|
|
|
|
if (mac_config[port].coe_rx)
|
|
tmpreg |= ETH_MACCONF_IPC;
|
|
|
|
writel(tmpreg, MAC(port, macconf));
|
|
|
|
/* (2) mactxfunc */
|
|
tmpreg = readl(MAC(port, mactxfunc));
|
|
|
|
writel(tmpreg, MAC(port, mactxfunc));
|
|
|
|
/* (3) macrxfunc */
|
|
tmpreg = readl(MAC(port, macrxfunc));
|
|
|
|
writel(tmpreg, MAC(port, macrxfunc));
|
|
|
|
/* (4) macfrmflt */
|
|
#if LWIP_IPV6
|
|
tmpreg = readl(MAC(port, macfrmflt));
|
|
tmpreg |= 0x80000001;
|
|
writel(tmpreg, MAC(port, macfrmflt));
|
|
#endif
|
|
|
|
/* (5) flowctl */
|
|
tmpreg = readl(MAC(port, flowctl));
|
|
tmpreg &= ~ETH_FLOWCTL_PT;
|
|
tmpreg |= (0x4 << ETH_FLOWCTL_PT_SHIFT);
|
|
writel(tmpreg, MAC(port, flowctl));
|
|
|
|
/*------------------------ DMA Configuration --------------------*/
|
|
/* (1) dma0conf */
|
|
tmpreg = readl(MAC(port, dma0conf));
|
|
tmpreg &= ~ETH_DMACONF_PR_MSK;
|
|
tmpreg |= ETH_DMACONF_PR_3_1;
|
|
tmpreg |= ETH_DMACONF_ATDS;
|
|
|
|
tmpreg |= ETH_DMACONF_USP;
|
|
tmpreg &= ~(ETH_DMACONF_RPBL_MSK | ETH_DMACONF_PBL_MSK);
|
|
tmpreg |= (mac_config[port].dma_rxpbl << ETH_DMACONF_RPBL_SHIFT);
|
|
tmpreg |= (mac_config[port].dma_txpbl << ETH_DMACONF_PBL_SHIFT);
|
|
|
|
if (mac_config[port].dma_pblx8)
|
|
tmpreg |= ETH_DMACONF_PBLx8;
|
|
else
|
|
tmpreg &= ~ETH_DMACONF_PBLx8;
|
|
|
|
if (mac_config[port].dma_fixed_burst)
|
|
tmpreg |= ETH_DMACONF_FB;
|
|
else
|
|
tmpreg &= ~ETH_DMACONF_FB;
|
|
|
|
if (mac_config[port].dma_mixed_burst)
|
|
tmpreg |= ETH_DMACONF_MB;
|
|
else
|
|
tmpreg &= ~ETH_DMACONF_MB;
|
|
|
|
if (mac_config[port].dma_aal)
|
|
tmpreg |= ETH_DMACONF_AAL;
|
|
else
|
|
tmpreg &= ~ETH_DMACONF_AAL;
|
|
|
|
writel(tmpreg, MAC(port, dma0conf));
|
|
|
|
/* (2) rxdma0ctl */
|
|
tmpreg = readl(MAC(port, rxdma0ctl));
|
|
if (mac_config[port].dma_sf_mode) {
|
|
tmpreg |= ETH_RXDMACTL_RSF;
|
|
} else {
|
|
tmpreg &= ~ETH_RXDMACTL_RSF;
|
|
tmpreg &= ~ETH_RXDMACTL_RTC_MSK;
|
|
tmpreg |= (mac_config[port].dma_fifo_rxth << ETH_RXDMACTL_RTC_SHIFT);
|
|
}
|
|
writel(tmpreg, MAC(port, rxdma0ctl));
|
|
|
|
/* (3) txdma0ctl */
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
if (mac_config[port].dma_sf_mode) {
|
|
tmpreg |= ETH_TXDMACTL_TSF;
|
|
} else {
|
|
tmpreg &= ~ETH_TXDMACTL_TSF;
|
|
tmpreg &= ~ETH_TXDMACTL_TTC_MSK;
|
|
tmpreg |= (mac_config[port].dma_fifo_txth << ETH_RXDMACTL_TTC_SHIFT);
|
|
}
|
|
writel(tmpreg, MAC(port, txdma0ctl));
|
|
|
|
#if !NO_SYS
|
|
/* (4) dma0inten */
|
|
tmpreg = readl(MAC(port, dma0inten));
|
|
tmpreg |= (ETH_DMAINTEN_NIE | ETH_DMAINTEN_RIE);
|
|
#ifdef CONFIG_MAC_ZERO_COPY_TXBUF
|
|
tmpreg |= ETH_DMAINTEN_TIE;
|
|
#endif
|
|
writel(tmpreg, MAC(port, dma0inten));
|
|
#endif
|
|
return ETH_SUCCESS;
|
|
}
|
|
|
|
void aicmac_start(uint32_t port)
|
|
{
|
|
/* Check the parameters */
|
|
assert_param(port < MAX_ETH_MAC_PORT);
|
|
|
|
/* Enable transmit state machine of the MAC for transmission on the MII */
|
|
aicmac_set_mac_tx(port, ENABLE);
|
|
|
|
/* Enable receive state machine of the MAC for reception from the MII */
|
|
aicmac_set_mac_rx(port, ENABLE);
|
|
|
|
/* Flush Transmit FIFO */
|
|
aicmac_flush_tx_fifo(port);
|
|
|
|
/* Start DMA transmission */
|
|
aicmac_set_dma_tx(port, ENABLE);
|
|
|
|
/* Start DMA reception */
|
|
aicmac_set_dma_rx(port, ENABLE);
|
|
}
|
|
|
|
void aicmac_stop(uint32_t port)
|
|
{
|
|
/* Check the parameters */
|
|
assert_param(port < MAX_ETH_MAC_PORT);
|
|
|
|
/* Stop DMA transmission */
|
|
aicmac_set_dma_tx(port, DISABLE);
|
|
|
|
/* Stop DMA reception */
|
|
aicmac_set_dma_rx(port, DISABLE);
|
|
|
|
/* Disable receive state machine of the MAC for reception from the MII */
|
|
aicmac_set_mac_rx(port, DISABLE);
|
|
|
|
/* Flush Transmit FIFO */
|
|
aicmac_flush_tx_fifo(port);
|
|
|
|
/* Disable transmit state machine of the MAC for transmission on the MII */
|
|
aicmac_set_mac_tx(port, DISABLE);
|
|
}
|
|
|
|
void aicmac_set_mac_speed(uint32_t port, int speed)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, macconf));
|
|
tmpreg &= ~ETH_MACCONF_SPEED_MSK;
|
|
if (speed == SPEED_1000) {
|
|
tmpreg |= ETH_MACCONF_SPEED_1000M;
|
|
} else if (speed == SPEED_100) {
|
|
tmpreg |= ETH_MACCONF_SPEED_100M;
|
|
} else if (speed == SPEED_10) {
|
|
tmpreg |= ETH_MACCONF_SPEED_10M;
|
|
}
|
|
writel(tmpreg, MAC(port, macconf));
|
|
}
|
|
|
|
void aicmac_set_mac_duplex(uint32_t port, bool state)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, macconf));
|
|
if (state)
|
|
tmpreg |= ETH_MACCONF_DM;
|
|
else
|
|
tmpreg &= ~ETH_MACCONF_DM;
|
|
writel(tmpreg, MAC(port, macconf));
|
|
}
|
|
|
|
void aicmac_set_mac_pause(uint32_t port, bool state)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, flowctl));
|
|
if (state)
|
|
tmpreg |= (ETH_FLOWCTL_RFE | ETH_FLOWCTL_TFE);
|
|
else
|
|
tmpreg &= ~(ETH_FLOWCTL_RFE | ETH_FLOWCTL_TFE);
|
|
writel(tmpreg, MAC(port, flowctl));
|
|
}
|
|
|
|
void aicmac_set_mac_tx(uint32_t port, bool state)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, mactxfunc));
|
|
if (state)
|
|
tmpreg |= ETH_MACTXFUNC_TE;
|
|
else
|
|
tmpreg &= ~ETH_MACTXFUNC_TE;
|
|
writel(tmpreg, MAC(port, mactxfunc));
|
|
}
|
|
|
|
void aicmac_set_mac_rx(uint32_t port, bool state)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, macrxfunc));
|
|
if (state)
|
|
tmpreg |= ETH_MACRXFUNC_RE;
|
|
else
|
|
tmpreg &= ~ETH_MACRXFUNC_RE;
|
|
writel(tmpreg, MAC(port, macrxfunc));
|
|
}
|
|
|
|
void aicmac_set_mac_addr(uint32_t port, uint32_t index, uint8_t *addr)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
/* Check the parameters */
|
|
assert_param(index < ETH_MACADDR_MAX_INDEX);
|
|
|
|
tmpreg = ((uint32_t)addr[5] << 8) | (uint32_t)addr[4];
|
|
writel(tmpreg, MAC(port, macaddr0high) + (index * 8));
|
|
tmpreg = ((uint32_t)addr[3] << 24) | ((uint32_t)addr[2] << 16) |
|
|
((uint32_t)addr[1] << 8) | addr[0];
|
|
writel(tmpreg, MAC(port, macaddr0low) + (index * 8));
|
|
}
|
|
|
|
void aicmac_get_mac_addr(uint32_t port, uint32_t index, uint8_t *addr)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
/* Check the parameters */
|
|
assert_param(index < ETH_MACADDR_MAX_INDEX);
|
|
|
|
tmpreg = readl(MAC(port, macaddr0high) + (index * 8));
|
|
addr[5] = ((tmpreg >> 8) & (uint8_t)0xFF);
|
|
addr[4] = (tmpreg & (uint8_t)0xFF);
|
|
tmpreg = readl(MAC(port, macaddr0low) + (index * 8));
|
|
addr[3] = ((tmpreg >> 24) & (uint8_t)0xFF);
|
|
addr[2] = ((tmpreg >> 16) & (uint8_t)0xFF);
|
|
addr[1] = ((tmpreg >> 8) & (uint8_t)0xFF);
|
|
addr[0] = (tmpreg & (uint8_t)0xFF);
|
|
}
|
|
|
|
void aicmac_set_mac_addr_mode(uint32_t port, uint32_t index, bool en, bool sa,
|
|
uint32_t mask)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
/* Check the parameters */
|
|
assert_param((index < ETH_MACADDR_MAX_INDEX) && (index > 0));
|
|
|
|
tmpreg = readl(MAC(port, macaddr0high) + (index * 8));
|
|
|
|
if (en)
|
|
tmpreg |= ETH_MACA1HR_AE;
|
|
else
|
|
tmpreg &= ~ETH_MACA1HR_AE;
|
|
|
|
if (sa)
|
|
tmpreg |= ETH_MACA1HR_SA;
|
|
else
|
|
tmpreg &= ~ETH_MACA1HR_SA;
|
|
|
|
tmpreg &= ~ETH_MACA1HR_MBC_MMSK;
|
|
tmpreg |= ((mask << ETH_MACA1HR_MBC_SHIFT) & ETH_MACA1HR_MBC_MMSK);
|
|
|
|
writel(tmpreg, MAC(port, macaddr0high) + (index * 8));
|
|
}
|
|
|
|
void aicmac_en_dma_int(uint32_t port, uint32_t interrupt)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, dma0inten));
|
|
tmpreg |= interrupt;
|
|
writel(tmpreg, MAC(port, dma0inten));
|
|
}
|
|
|
|
void aicmac_dis_dma_int(uint32_t port, uint32_t interrupt)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, dma0inten));
|
|
tmpreg &= ~interrupt;
|
|
writel(tmpreg, MAC(port, dma0inten));
|
|
}
|
|
|
|
void aicmac_resume_dma_rx(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
#if 0
|
|
/* When Rx Buffer unavailable flag is set: clear it and resume receive */
|
|
tmpreg = readl(MAC(port, dma0intsts));
|
|
if (tmpreg & ETH_DMAINTSTS_RU) {
|
|
tmpreg |= ETH_DMAINTSTS_RU;
|
|
writel(tmpreg, MAC(port, dma0intsts));
|
|
|
|
tmpreg = readl(MAC(port, rxdma0ctl));
|
|
tmpreg |= ETH_RXDMACTL_RPD;
|
|
writel(tmpreg, MAC(port, rxdma0ctl));
|
|
}
|
|
#else
|
|
tmpreg = readl(MAC(port, rxdma0ctl));
|
|
tmpreg |= ETH_RXDMACTL_RPD;
|
|
writel(tmpreg, MAC(port, rxdma0ctl));
|
|
#endif
|
|
|
|
}
|
|
|
|
void aicmac_resume_dma_tx(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
#if 0
|
|
tmpreg = readl(MAC(port, dma0intsts));
|
|
if (tmpreg & ETH_DMAINTSTS_TU) {
|
|
tmpreg |= ETH_DMAINTSTS_TU;
|
|
writel(tmpreg, MAC(port, dma0intsts));
|
|
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
tmpreg |= ETH_TXDMACTL_TPD;
|
|
writel(tmpreg, MAC(port, txdma0ctl));
|
|
}
|
|
#else
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
tmpreg |= ETH_TXDMACTL_TPD;
|
|
writel(tmpreg, MAC(port, txdma0ctl));
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
void aicmac_dma_rx_desc_init(uint32_t port)
|
|
{
|
|
uint32_t i = 0;
|
|
aicmac_dma_desc_t *rxdesc_tbl = &dctl[port].rx_desc_tbl[0];
|
|
uint32_t count = ETH_RXBUFNB;
|
|
aicmac_dma_desc_t *pdesc;
|
|
#ifndef CONFIG_MAC_ZERO_COPY_RXBUF
|
|
uint8_t *buff = &dctl[port].rx_buff[0][0];
|
|
#else
|
|
struct pbuf *p = NULL;
|
|
#endif
|
|
|
|
memset(rxdesc_tbl, 0, sizeof(aicmac_dma_desc_t) * count);
|
|
for (i = 0; i < count; i++) {
|
|
pdesc = rxdesc_tbl + i;
|
|
|
|
/* Set Own bit of the Rx descriptor Status */
|
|
pdesc->control = ETH_DMARxDesc_OWN;
|
|
|
|
#ifndef CONFIG_MAC_ZERO_COPY_RXBUF
|
|
/* Set Buffer1 size and Second Address Chained bit */
|
|
pdesc->buff_size =
|
|
ETH_DMARxDesc_RCH | (ETH_RX_BUF_SIZE & ETH_DMARxDesc_RBS1);
|
|
/* Set Buffer1 address pointer */
|
|
pdesc->buff1_addr =
|
|
(uint32_t)(unsigned long)(&buff[i * ETH_RX_BUF_SIZE]);
|
|
pdesc->reserved1 = i;
|
|
#else
|
|
/* get a pbuf from PBUF_POOL */
|
|
p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL);
|
|
if (p == NULL) {
|
|
pr_err("%s pbuf_alloc fail!\n", __func__);
|
|
return;
|
|
}
|
|
p->tot_len = AICMAC_PBUF_SIZE;
|
|
p->len = AICMAC_PBUF_SIZE;
|
|
dctl[port].rx_buff[i] = p;
|
|
/* Set Buffer1 size and Second Address Chained bit */
|
|
pdesc->buff_size =
|
|
ETH_DMARxDesc_RCH | (AICMAC_PBUF_SIZE & ETH_DMARxDesc_RBS1);
|
|
/* Set Buffer1 address pointer */
|
|
pdesc->buff1_addr = (uint32_t)(unsigned long)(p->payload);
|
|
pdesc->reserved1 = i;
|
|
aicmac_dcache_clean((uintptr_t)p, sizeof(struct pbuf));
|
|
#endif
|
|
|
|
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
|
|
if (i < (count - 1)) {
|
|
/* Set next descriptor address register with next descriptor base address */
|
|
pdesc->buff2_addr =
|
|
(uint32_t)(unsigned long)(rxdesc_tbl + i + 1);
|
|
} else {
|
|
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
|
|
pdesc->buff2_addr = (uint32_t)(unsigned long)rxdesc_tbl;
|
|
}
|
|
}
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)rxdesc_tbl, sizeof(aicmac_dma_desc_t) * count);
|
|
|
|
writel((uint32_t)(unsigned long)rxdesc_tbl, MAC(port, rxdma0descstart));
|
|
|
|
dctl[port].rx_desc_p = rxdesc_tbl;
|
|
dctl[port].rx_desc_received_p = rxdesc_tbl;
|
|
dctl[port].rx_desc_unrelease_p = rxdesc_tbl;
|
|
dctl[port].rx_frame_info_p = &dctl[port].rx_frame_info;
|
|
}
|
|
|
|
void aicmac_dma_tx_desc_init(uint32_t port)
|
|
{
|
|
uint32_t i = 0;
|
|
aicmac_dma_desc_t *txdesc_tbl = &dctl[port].tx_desc_tbl[0];
|
|
#ifndef CONFIG_MAC_ZERO_COPY_TXBUF
|
|
uint8_t *buff = &dctl[port].tx_buff[0][0];
|
|
#endif
|
|
uint32_t count = ETH_TXBUFNB;
|
|
aicmac_dma_desc_t *pdesc;
|
|
|
|
memset(txdesc_tbl, 0, sizeof(aicmac_dma_desc_t) * count);
|
|
for (i = 0; i < count; i++) {
|
|
pdesc = txdesc_tbl + i;
|
|
|
|
/* Set Second Address Chained bit */
|
|
pdesc->control = ETH_DMATxDesc_TCH;
|
|
|
|
#ifdef LWIP_PTP
|
|
pdesc->control |= ETH_DMATxDesc_TTSE;
|
|
#endif
|
|
|
|
#ifndef CONFIG_MAC_ZERO_COPY_TXBUF
|
|
/* Set Buffer1 address pointer */
|
|
pdesc->buff1_addr =
|
|
(uint32_t)(unsigned long)(&buff[i * ETH_TX_BUF_SIZE]);
|
|
#else
|
|
pdesc->reserved1 = i;
|
|
dctl[port].tx_buff[i] = NULL;
|
|
#endif
|
|
|
|
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
|
|
if (i < (count - 1)) {
|
|
/* Set next descriptor address register with next descriptor base address */
|
|
pdesc->buff2_addr =
|
|
(uint32_t)(unsigned long)(txdesc_tbl + i + 1);
|
|
} else {
|
|
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
|
|
pdesc->buff2_addr = (uint32_t)(unsigned long)txdesc_tbl;
|
|
}
|
|
}
|
|
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)txdesc_tbl, sizeof(aicmac_dma_desc_t) * count);
|
|
|
|
writel((uint32_t)(unsigned long)txdesc_tbl, MAC(port, txdma0descstart));
|
|
|
|
dctl[port].tx_desc_p = txdesc_tbl;
|
|
#ifdef CONFIG_MAC_ZERO_COPY_TXBUF
|
|
dctl[port].tx_desc_unconfirm_p = txdesc_tbl;
|
|
#endif
|
|
}
|
|
|
|
uint32_t aicmac_check_rx_frame_poll(uint32_t port)
|
|
{
|
|
aicmac_dma_desc_t *pdesc = dctl[port].rx_desc_p;
|
|
aicmac_rx_frame_info_t *pinfo = dctl[port].rx_frame_info_p;
|
|
|
|
/* before read: invalid cache */
|
|
aicmac_dcache_invalid((uintptr_t)pdesc, sizeof(aicmac_dma_desc_t));
|
|
|
|
/* check if last segment */
|
|
if (((pdesc->control & ETH_DMARxDesc_OWN) == (uint32_t)RESET)
|
|
&& ((pdesc->control & ETH_DMARxDesc_LS) != (uint32_t)RESET)) {
|
|
|
|
if ((pdesc->control & ETH_DMARxDesc_FS) != (uint32_t)RESET)
|
|
pinfo->seg_cnt = 1;
|
|
else
|
|
pinfo->seg_cnt++;
|
|
|
|
if (pinfo->seg_cnt == 1) {
|
|
pinfo->first_desc = pdesc;
|
|
}
|
|
pinfo->last_desc = pdesc;
|
|
return 1;
|
|
|
|
/* check if first segment */
|
|
} else if (((pdesc->control & ETH_DMARxDesc_OWN) == (uint32_t)RESET)
|
|
&& ((pdesc->control & ETH_DMARxDesc_FS) != (uint32_t)RESET)
|
|
&& ((pdesc->control & ETH_DMARxDesc_LS) == (uint32_t)RESET)) {
|
|
pinfo->first_desc = pdesc;
|
|
pinfo->last_desc = NULL;
|
|
pinfo->seg_cnt = 1;
|
|
dctl[port].rx_desc_p =
|
|
(aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
|
|
/* check if intermediate segment */
|
|
} else if (((pdesc->control & ETH_DMARxDesc_OWN) == (uint32_t)RESET) &&
|
|
((pdesc->control & ETH_DMARxDesc_FS) == (uint32_t)RESET) &&
|
|
((pdesc->control & ETH_DMARxDesc_LS) == (uint32_t)RESET)) {
|
|
(pinfo->seg_cnt)++;
|
|
dctl[port].rx_desc_p =
|
|
(aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
aicmac_frame_t aicmac_get_rx_frame_poll(uint32_t port)
|
|
{
|
|
aicmac_dma_desc_t *pdesc = dctl[port].rx_desc_p;
|
|
aicmac_rx_frame_info_t *pinfo = dctl[port].rx_frame_info_p;
|
|
uint32_t framelength = 0;
|
|
aicmac_frame_t frame = { 0, 0, 0 };
|
|
|
|
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
|
|
framelength = ((pdesc->control & ETH_DMARxDesc_FL) >>
|
|
ETH_DMARxDesc_FL_SHIFT) - 4;
|
|
frame.length = framelength;
|
|
|
|
/* Get the address of the first frame descriptor and the buffer start address */
|
|
frame.descriptor = pinfo->first_desc;
|
|
frame.buffer = (pinfo->first_desc)->buff1_addr;
|
|
frame.last_desc = pinfo->last_desc;
|
|
|
|
/* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
|
|
/* Chained Mode */
|
|
/* Selects the next DMA Rx descriptor list for next buffer to read */
|
|
dctl[port].rx_desc_p =
|
|
(aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
|
|
/* Return Frame */
|
|
return (frame);
|
|
}
|
|
|
|
aicmac_frame_t aicmac_get_rx_frame_interrupt(uint32_t port)
|
|
{
|
|
aicmac_dma_desc_t *pdesc = dctl[port].rx_desc_p;
|
|
aicmac_rx_frame_info_t *pinfo = dctl[port].rx_frame_info_p;
|
|
aicmac_frame_t frame = { 0, 0, 0, 0 };
|
|
uint32_t descriptor_scan_counter = 0;
|
|
|
|
/* before read: invalid cache */
|
|
aicmac_dcache_invalid((uintptr_t)pdesc, sizeof(aicmac_dma_desc_t));
|
|
|
|
/* scan descriptors owned by CPU */
|
|
while (((pdesc->control & ETH_DMARxDesc_OWN) == (uint32_t)RESET) &&
|
|
(descriptor_scan_counter < ETH_RXBUFNB)) {
|
|
/* Just by security */
|
|
descriptor_scan_counter++;
|
|
|
|
/* check if first segment in frame */
|
|
if (((pdesc->control & ETH_DMARxDesc_FS) != (uint32_t)RESET) &&
|
|
((pdesc->control & ETH_DMARxDesc_LS) == (uint32_t)RESET)) {
|
|
pinfo->first_desc = pdesc;
|
|
pinfo->seg_cnt = 1;
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
dctl[port].rx_desc_p = pdesc;
|
|
|
|
/* check if intermediate segment */
|
|
} else if (((pdesc->control & ETH_DMARxDesc_LS) == (uint32_t)RESET) &&
|
|
((pdesc->control & ETH_DMARxDesc_FS) == (uint32_t)RESET)) {
|
|
(pinfo->seg_cnt)++;
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
dctl[port].rx_desc_p = pdesc;
|
|
|
|
/* should be last segment */
|
|
} else {
|
|
/* last segment */
|
|
pinfo->last_desc = pdesc;
|
|
(pinfo->seg_cnt)++;
|
|
|
|
/* first segment is last segment */
|
|
if ((pinfo->seg_cnt) == 1)
|
|
pinfo->first_desc = pdesc;
|
|
|
|
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
|
|
frame.length = ((pdesc->control & ETH_DMARxDesc_FL) >>
|
|
ETH_DMARxDesc_FL_SHIFT) -
|
|
4;
|
|
|
|
/* Get the address of the buffer start address */
|
|
/* Check if more than one segment in the frame */
|
|
if (pinfo->seg_cnt > 1)
|
|
frame.buffer = (pinfo->first_desc)->buff1_addr;
|
|
else
|
|
frame.buffer = pdesc->buff1_addr;
|
|
|
|
frame.descriptor = pinfo->first_desc;
|
|
frame.last_desc = pinfo->last_desc;
|
|
|
|
/* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
dctl[port].rx_desc_p = pdesc;
|
|
|
|
/* Return Frame */
|
|
return (frame);
|
|
}
|
|
|
|
/* before read: invalid cache */
|
|
aicmac_dcache_invalid((uintptr_t)pdesc, sizeof(aicmac_dma_desc_t));
|
|
}
|
|
return (frame);
|
|
}
|
|
|
|
void aicmac_release_rx_frame(uint32_t port)
|
|
{
|
|
aicmac_dma_desc_t *pdesc = dctl[port].rx_desc_unrelease_p;
|
|
aicmac_dma_desc_t *pdesc_end = dctl[port].rx_desc_received_p;
|
|
#ifdef CONFIG_MAC_ZERO_COPY_RXBUF
|
|
uint32_t index = 0;
|
|
struct pbuf *p = NULL;
|
|
#endif
|
|
|
|
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
|
|
while(pdesc != pdesc_end) {
|
|
#ifdef CONFIG_MAC_ZERO_COPY_RXBUF
|
|
index = pdesc->reserved1;
|
|
if (index >= ETH_RXBUFNB) {
|
|
pr_err("%s get dma desc index err.\n", __func__);
|
|
return;
|
|
}
|
|
/* get a pbuf from PBUF_POOL */
|
|
p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL);
|
|
if (p == NULL) {
|
|
pr_info("%s rx pbuf_alloc fail!\n", __func__);
|
|
dctl[port].rx_buf_underrun = 1;
|
|
return;
|
|
}
|
|
p->tot_len = AICMAC_PBUF_SIZE;
|
|
p->len = AICMAC_PBUF_SIZE;
|
|
dctl[port].rx_buff[index] = p;
|
|
/* Set Buffer1 size and Second Address Chained bit */
|
|
pdesc->buff_size =
|
|
ETH_DMARxDesc_RCH | (AICMAC_PBUF_SIZE & ETH_DMARxDesc_RBS1);
|
|
/* Set Buffer1 address pointer */
|
|
pdesc->buff1_addr =
|
|
(uint32_t)(unsigned long)(p->payload);
|
|
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)&pdesc->buff_size, 2*sizeof(uint32_t));
|
|
aicmac_dcache_clean((uintptr_t)p, sizeof(struct pbuf));
|
|
#endif
|
|
|
|
pdesc->control = ETH_DMARxDesc_OWN;
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)&pdesc->control, sizeof(uint32_t));
|
|
|
|
/* Point to next descriptor */
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
dctl[port].rx_desc_unrelease_p = pdesc;
|
|
}
|
|
|
|
#ifdef CONFIG_MAC_ZERO_COPY_RXBUF
|
|
if (dctl[port].rx_buf_underrun) {
|
|
pr_info("%s rx pbuf underrun resume!\n", __func__);
|
|
dctl[port].rx_buf_underrun = 0;
|
|
}
|
|
#endif
|
|
|
|
/* Resume DMA receive */
|
|
aicmac_resume_dma_rx(port);
|
|
}
|
|
|
|
int aicmac_submit_tx_frame(uint32_t port, u16 frame_len)
|
|
{
|
|
uint32_t buf_count = 0, size = 0, i = 0;
|
|
uint32_t tmpreg = 0;
|
|
aicmac_dma_desc_t *pdesc = dctl[port].tx_desc_p;
|
|
|
|
/* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
|
|
if ((pdesc->control & ETH_DMATxDesc_OWN) != (u32)RESET) {
|
|
/* Return ERROR: OWN bit set */
|
|
return ETH_ERROR;
|
|
}
|
|
|
|
if (frame_len > ETH_TX_BUF_SIZE) {
|
|
buf_count = frame_len / ETH_TX_BUF_SIZE;
|
|
if (frame_len % ETH_TX_BUF_SIZE)
|
|
buf_count++;
|
|
} else {
|
|
buf_count = 1;
|
|
}
|
|
|
|
if (buf_count == 1) {
|
|
/* Set frame size */
|
|
pdesc->buff_size = (frame_len & ETH_DMATxDesc_TBS1);
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)&pdesc->buff_size, sizeof(uint32_t));
|
|
/*set LAST and FIRST segment */
|
|
//tmpreg = pdesc->control;
|
|
tmpreg = ETH_DMATxDesc_TCH;
|
|
tmpreg |= ETH_DMATxDesc_FS | ETH_DMATxDesc_LS;
|
|
/* TCP/IP Tx Checksum Insertion */
|
|
if (mac_config[port].coe_tx)
|
|
tmpreg |= ETH_DMATxDesc_CIC_TCPUDPICMP_Full;
|
|
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
|
|
tmpreg |= ETH_DMATxDesc_OWN;
|
|
pdesc->control = tmpreg;
|
|
|
|
#ifdef LWIP_PTP
|
|
pdesc->control |= ETH_DMATxDesc_TTSE;
|
|
#endif
|
|
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)&pdesc->control, sizeof(uint32_t));
|
|
/* update */
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
} else {
|
|
for (i = 0; i < buf_count; i++) {
|
|
/* Clear FIRST and LAST segment bits */
|
|
pdesc->control &= ~(ETH_DMATxDesc_FS | ETH_DMATxDesc_LS);
|
|
|
|
if (i == 0) {
|
|
/* Setting the first segment bit */
|
|
pdesc->control |= ETH_DMATxDesc_FS;
|
|
}
|
|
|
|
/* Program size */
|
|
pdesc->buff_size = (ETH_TX_BUF_SIZE & ETH_DMATxDesc_TBS1);
|
|
|
|
if (i == (buf_count - 1)) {
|
|
/* Setting the last segment bit */
|
|
pdesc->control |= ETH_DMATxDesc_LS;
|
|
size = frame_len - (buf_count - 1) * ETH_TX_BUF_SIZE;
|
|
pdesc->buff_size = (size & ETH_DMATxDesc_TBS1);
|
|
}
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)&pdesc->buff_size, sizeof(uint32_t));
|
|
|
|
/* TCP/IP Tx Checksum Insertion */
|
|
if (mac_config[port].coe_tx)
|
|
tmpreg |= ETH_DMATxDesc_CIC_TCPUDPICMP_Full;
|
|
|
|
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
|
|
pdesc->control |= ETH_DMATxDesc_OWN;
|
|
|
|
#ifdef LWIP_PTP
|
|
pdesc->control |= ETH_DMATxDesc_TTSE;
|
|
#endif
|
|
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)&pdesc->control, sizeof(uint32_t));
|
|
/* update */
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
}
|
|
}
|
|
|
|
dctl[port].tx_desc_p = pdesc;
|
|
|
|
/* Resume DMA transmission */
|
|
aicmac_resume_dma_tx(port);
|
|
|
|
/* Return SUCCESS */
|
|
return ETH_SUCCESS;
|
|
}
|
|
|
|
void aicmac_confirm_tx_frame(uint32_t port)
|
|
{
|
|
#ifdef CONFIG_MAC_ZERO_COPY_TXBUF
|
|
aicmac_dma_desc_t *pdesc = dctl[port].tx_desc_unconfirm_p;
|
|
aicmac_dma_desc_t *pdesc_end = dctl[port].tx_desc_p;
|
|
struct pbuf *p;
|
|
uint32_t index;
|
|
|
|
if (pdesc == pdesc_end)
|
|
return;
|
|
|
|
/* before read: invalid cache */
|
|
aicmac_dcache_invalid((uintptr_t)pdesc, sizeof(aicmac_dma_desc_t));
|
|
|
|
/* scan descriptors owned by CPU */
|
|
while ((pdesc != pdesc_end) &&
|
|
((pdesc->control & ETH_DMARxDesc_OWN) == (uint32_t)RESET)) {
|
|
|
|
index = pdesc->reserved1;
|
|
if (index >= ETH_RXBUFNB) {
|
|
pr_err("%s get dma desc index err.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
p = dctl[port].tx_buff[index];
|
|
if (p != NULL) {
|
|
pbuf_free(p);
|
|
dctl[port].tx_buff[index] = NULL;
|
|
}
|
|
|
|
/* next pointer */
|
|
pdesc = (aicmac_dma_desc_t *)(unsigned long)(pdesc->buff2_addr);
|
|
/* before read: invalid cache */
|
|
aicmac_dcache_invalid((uintptr_t)pdesc, sizeof(aicmac_dma_desc_t));
|
|
}
|
|
|
|
dctl[port].tx_desc_unconfirm_p = pdesc;
|
|
|
|
/* Resume DMA transmission */
|
|
aicmac_resume_dma_tx(port);
|
|
#endif
|
|
}
|
|
|
|
void aicmac_set_dma_tx_desc_int(uint32_t port, bool en)
|
|
{
|
|
aicmac_dma_desc_t *prxdesc;
|
|
uint32_t count = ETH_TXBUFNB;
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
prxdesc = &dctl[port].tx_desc_tbl[i];
|
|
if (en) {
|
|
/* Enable the DMA Tx Desc Transmit interrupt */
|
|
prxdesc->control |= ETH_DMATxDesc_IC;
|
|
} else {
|
|
/* Disable the DMA Tx Desc Transmit interrupt */
|
|
prxdesc->control &= (~(uint32_t)ETH_DMATxDesc_IC);
|
|
}
|
|
}
|
|
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)prxdesc, sizeof(aicmac_dma_desc_t) * count);
|
|
}
|
|
|
|
void aicmac_set_dma_rx_desc_int(uint32_t port, bool en)
|
|
{
|
|
aicmac_dma_desc_t *prxdesc;
|
|
uint32_t count = ETH_RXBUFNB;
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
prxdesc = &dctl[port].rx_desc_tbl[i];
|
|
if (en) {
|
|
/* Enable the DMA Rx Desc receive interrupt */
|
|
prxdesc->buff_size &= (~(uint32_t)ETH_DMARxDesc_DIC);
|
|
} else {
|
|
/* Disable the DMA Rx Desc receive interrupt */
|
|
prxdesc->buff_size |= ETH_DMARxDesc_DIC;
|
|
}
|
|
}
|
|
|
|
/* after write: flush cache */
|
|
aicmac_dcache_clean((uintptr_t)prxdesc, sizeof(aicmac_dma_desc_t) * count);
|
|
}
|
|
|
|
void aicmac_sw_reset(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
uint32_t timeout = 0;
|
|
|
|
tmpreg = readl(MAC(port, macconf));
|
|
tmpreg |= ETH_MACCONF_SWR;
|
|
writel(tmpreg, MAC(port, macconf));
|
|
|
|
/* Check for the Busy flag */
|
|
do {
|
|
timeout++;
|
|
tmpreg = readl(MAC(port, macconf));
|
|
} while ((tmpreg & ETH_MACCONF_SWR) && (timeout < (uint32_t)PHY_WRITE_TO));
|
|
|
|
if (timeout == PHY_WRITE_TO) {
|
|
pr_err("aicmac software reset timeout.\n");
|
|
}
|
|
}
|
|
|
|
bool aicmac_get_sw_reset_status(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, macconf));
|
|
if (tmpreg & ETH_MACCONF_SWR)
|
|
return SET;
|
|
else
|
|
return RESET;
|
|
}
|
|
|
|
bool aicmac_get_dma_int_status(uint32_t port, uint32_t flag)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, dma0intsts));
|
|
if (tmpreg & flag)
|
|
return SET;
|
|
else
|
|
return RESET;
|
|
}
|
|
|
|
void aicmac_clear_dma_int_pending(uint32_t port, uint32_t flag)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, dma0intsts));
|
|
tmpreg |= flag;
|
|
writel(tmpreg, MAC(port, dma0intsts));
|
|
}
|
|
|
|
uint32_t aicmac_get_dma_tx_state(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, dma0intsts));
|
|
tmpreg = (tmpreg & ETH_DMAINTSTS_TS_MSK) >> ETH_DMAINTSTS_TS_SHIFT;
|
|
return tmpreg;
|
|
}
|
|
|
|
uint32_t aicmac_get_dma_rx_state(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, dma0intsts));
|
|
tmpreg = (tmpreg & ETH_DMAINTSTS_RS_MSK) >> ETH_DMAINTSTS_RS_SHIFT;
|
|
return tmpreg;
|
|
}
|
|
|
|
void aicmac_flush_tx_fifo(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
uint32_t timeout = 0;
|
|
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
tmpreg |= ETH_TXDMACTL_FTF;
|
|
writel(tmpreg, MAC(port, txdma0ctl));
|
|
|
|
/* Check for the Busy flag */
|
|
do {
|
|
timeout++;
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
} while ((tmpreg & ETH_TXDMACTL_FTF) && (timeout < (uint32_t)PHY_WRITE_TO));
|
|
}
|
|
|
|
bool aicmac_get_flush_tx_fifo_status(uint32_t port)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
if (tmpreg & ETH_TXDMACTL_FTF)
|
|
return SET;
|
|
else
|
|
return RESET;
|
|
}
|
|
|
|
void aicmac_set_dma_tx(uint32_t port, bool state)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, txdma0ctl));
|
|
if (state)
|
|
tmpreg |= ETH_TXDMACTL_ST;
|
|
else
|
|
tmpreg &= ~ETH_TXDMACTL_ST;
|
|
writel(tmpreg, MAC(port, txdma0ctl));
|
|
}
|
|
|
|
void aicmac_set_dma_rx(uint32_t port, bool state)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
|
|
tmpreg = readl(MAC(port, rxdma0ctl));
|
|
if (state)
|
|
tmpreg |= ETH_RXDMACTL_SR;
|
|
else
|
|
tmpreg &= ~ETH_RXDMACTL_SR;
|
|
writel(tmpreg, MAC(port, rxdma0ctl));
|
|
}
|
|
|
|
int aicmac_read_phy_reg(uint32_t port, uint32_t addr, uint16_t *val)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
uint32_t timeout = 0;
|
|
|
|
tmpreg = readl(MAC(port, mdioctl));
|
|
tmpreg &= ETH_MDIOCTL_CR_MSK;
|
|
tmpreg |= (((uint32_t)mac_config[port].phyaddr << 11) &
|
|
ETH_MDIOCTL_PA); /* Set the PHY device address */
|
|
tmpreg |= (((uint32_t)addr << 6) &
|
|
ETH_MDIOCTL_MR); /* Set the PHY register address */
|
|
tmpreg &= ~ETH_MDIOCTL_MW; /* Set the read mode */
|
|
tmpreg |= ETH_MDIOCTL_MB; /* Set the MII Busy bit */
|
|
writel(tmpreg, MAC(port, mdioctl));
|
|
|
|
/* Check for the Busy flag */
|
|
do {
|
|
timeout++;
|
|
tmpreg = readl(MAC(port, mdioctl));
|
|
} while ((tmpreg & ETH_MDIOCTL_MB) && (timeout < (uint32_t)PHY_WRITE_TO));
|
|
|
|
if (timeout == PHY_WRITE_TO) {
|
|
pr_err("aicmac port%d read phy %d reg %d timeout.\n", (int)port,
|
|
(int)mac_config[port].phyaddr, (int)addr);
|
|
return ETH_ERROR;
|
|
}
|
|
|
|
tmpreg = readl(MAC(port, mdiodata));
|
|
*val = tmpreg & 0xFFFF;
|
|
return ETH_SUCCESS;
|
|
}
|
|
|
|
int aicmac_write_phy_reg(uint32_t port, uint32_t addr, uint16_t val)
|
|
{
|
|
uint32_t tmpreg = 0;
|
|
uint32_t timeout = 0;
|
|
|
|
tmpreg = readl(MAC(port, mdioctl));
|
|
tmpreg &= ETH_MDIOCTL_CR_MSK;
|
|
tmpreg |= (((uint32_t)mac_config[port].phyaddr << 11) &
|
|
ETH_MDIOCTL_PA); /* Set the PHY device address */
|
|
tmpreg |= (((uint32_t)addr << 6) &
|
|
ETH_MDIOCTL_MR); /* Set the PHY register address */
|
|
tmpreg |= ETH_MDIOCTL_MW; /* Set the write mode */
|
|
tmpreg |= ETH_MDIOCTL_MB; /* Set the MII Busy bit */
|
|
writel(val, MAC(port, mdiodata));
|
|
writel(tmpreg, MAC(port, mdioctl));
|
|
|
|
/* Check for the Busy flag */
|
|
do {
|
|
timeout++;
|
|
tmpreg = readl(MAC(port, mdioctl));
|
|
} while ((tmpreg & ETH_MDIOCTL_MB) && (timeout < (uint32_t)PHY_WRITE_TO));
|
|
|
|
if (timeout == PHY_WRITE_TO) {
|
|
pr_err("aicmac port%d write phy %d reg %d timeout.\n", (int)port,
|
|
(int)mac_config[port].phyaddr, (int)addr);
|
|
return ETH_ERROR;
|
|
}
|
|
|
|
return ETH_SUCCESS;
|
|
}
|
|
|
|
#define AICMAC_PTP_NANO_SEC_REG_SET 1
|
|
u32_t nanosecond2subsecond(u32_t nanosecond)
|
|
{
|
|
#if AICMAC_PTP_NANO_SEC_REG_SET
|
|
return nanosecond;
|
|
#else
|
|
uint64_t val = nanosecond * 0x80000000ll;
|
|
val /= 1000000000;
|
|
return val;
|
|
#endif
|
|
}
|
|
|
|
u32_t subsecond2nanosecond(u32_t subsecond)
|
|
{
|
|
#if AICMAC_PTP_NANO_SEC_REG_SET
|
|
return subsecond;
|
|
#else
|
|
uint64_t val = ((uint64_t)subsecond * 1000000000) / 0x80000000ll;
|
|
return val;
|
|
#endif
|
|
}
|
|
|
|
aicmac_timestamp_t aicmac_get_rx_timestamp(uint32_t port, aicmac_frame_t *frame)
|
|
{
|
|
aicmac_timestamp_t timestamp = {0};
|
|
aicmac_dma_desc_t *pdesc = frame->last_desc;
|
|
|
|
if ((pdesc->control & (ETH_DMARxDesc_LS | ETH_DMARxDesc_IPV4HCE)) == \
|
|
(ETH_DMARxDesc_LS | ETH_DMARxDesc_IPV4HCE)) {
|
|
timestamp.second = pdesc->timestamp_high;
|
|
timestamp.nanosecond = subsecond2nanosecond(pdesc->timestamp_low);
|
|
|
|
//printf(">>>>>>>Get rx timestamp, %d, %d\n",timestamp.second, timestamp.nanosecond);
|
|
}
|
|
|
|
return timestamp;
|
|
}
|
|
|
|
aicmac_timestamp_t aicmac_get_tx_timestamp(uint32_t port, aicmac_dma_desc_t *pdesc)
|
|
{
|
|
aicmac_timestamp_t timestamp = {0};
|
|
|
|
if ((pdesc->control & (ETH_DMATxDesc_LS | ETH_DMATxDesc_TTSS)) == \
|
|
(ETH_DMATxDesc_LS | ETH_DMATxDesc_TTSS)) {
|
|
|
|
timestamp.second = pdesc->timestamp_high;
|
|
timestamp.nanosecond = subsecond2nanosecond(pdesc->timestamp_low);
|
|
|
|
// printf("<<<<<<<<<<Get tx timestamp, %d, %d\n",timestamp.second, timestamp.nanosecond);
|
|
}
|
|
|
|
return timestamp;
|
|
}
|
|
|