rustl8710/component/soc/realtek/8195a/fwlib/rtl8195a/src/rtl8195a_mii.c
2016-12-30 18:23:39 -05:00

1081 lines
27 KiB
C

/*
* Routines to access hardware
*
* Copyright (c) 2013 Realtek Semiconductor Corp.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*/
#include "rtl8195a.h"
#include "rtl8195a_mii.h"
#include "hal_mii.h"
#include "osdep_api.h"
//#include "hal_gdma.h"
volatile u8 *pTxDataBuf = NULL;
volatile u8 *pRxDataBuf = NULL;
#if 0
volatile TX_DESC_FMT TxDesc[MII_TX_DESC_NO];
volatile RX_DESC_FMT RxDesc[MII_RX_DESC_NO];
volatile u32 TxDescIdx = 0;
volatile u32 TxBufIdx = 0;
volatile u32 RxDescIdx = 0;
volatile u32 RxBufIdx = 0;
volatile u8 isTxDone = 0;
volatile u8 isRxDone = 0;
volatile u32 CurrDataLen = 0;
volatile u32 ReadDescIdx = 0;
volatile u32 ReadBufIdx = 0;
volatile u32 CurrSentSize = 0;
volatile u32 CurrReceivedSize = 0;
#endif
// by jimmy
volatile PTX_DESC_FMT TxDesc;
volatile PRX_DESC_FMT RxDesc;
volatile u8 TxDescWrPtr = 0;
volatile u8 RxDescRdPtr = 0;
volatile u32 CurrDataLen = 0;
#if 0
HAL_GDMA_OBJ gdmaObj;
u8 isGdmaAllocated;
volatile u8 isDmaDone;
#endif
extern HAL_ETHER_ADAPTER HalEtherAdp;
VOID Mii_ISR(
IN VOID *Data
)
{
PHAL_ETHER_ADAPTER pEthAdapter = (PHAL_ETHER_ADAPTER) Data;
volatile u32 RegValue = HAL_MII_READ32(REG_MII_ISRIMR);
if((RegValue & ISR_RXOK) && ((pEthAdapter->InterruptMask) & IMR_RXOK))
{
/* Disable interrupt and enbale again when the rx descriptor ring is empty */
pEthAdapter->InterruptMask &= (~IMR_RXOK);
if(pEthAdapter->CallBack != NULL)
{
pEthAdapter->CallBack(ETH_RXDONE, 0); // receive size is meanless here
}
}
if((RegValue & ISR_RER_OVF) && ((pEthAdapter->InterruptMask) & IMR_RER_OVF))
{
DBG_MII_WARN("ISR_RER_OVF 0x%08X \n", RegValue);
/* Ignore this interrupt, rx thread will clean the OWN bit */
pEthAdapter->InterruptMask &= (~ISR_RER_OVF);
}
if((RegValue & ISR_TXOK) && ((pEthAdapter->InterruptMask) & IMR_TXOK))
{
/* Disable TxOK interrupt */
pEthAdapter->InterruptMask &= (~IMR_TXOK);
/* User callback function */
if(pEthAdapter->CallBack != NULL)
{
pEthAdapter->CallBack(ETH_TXDONE, 0);
}
}
if((RegValue & ISR_LINKCHG) && ((pEthAdapter->InterruptMask) & IMR_LINKCHG))
{
if(pEthAdapter->CallBack != NULL)
{
if(HAL_MII_READ32(REG_MII_MS) & MS_LINKB)
{
pEthAdapter->CallBack(ETH_LINKDOWN, 0);
}
else
{
pEthAdapter->CallBack(ETH_LINKUP, 0);
}
}
}
HAL_MII_WRITE32(REG_MII_ISRIMR, (pEthAdapter->InterruptMask) | ISR_CLR_ALL);
}
u16
HalMiiRwPhyRegRtl8195a(u8 Operation, u8 Address, u16 Data)
{
u32 tmp;
tmp = (Operation << 31) | ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((Address << 16) & MIIA_PHY_REG_ADDR_MASK) | Data;
HAL_MII_WRITE32(REG_MII_MIIA, tmp);
HalDelayUs(1000);
if(Operation)
{
/* Wait for write operation is completed */
do {
}while(HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG);
return 0;
}
else
{
/* Wait for read operation is completed */
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
return (u16)(HAL_MII_READ32(REG_MII_MIIA) & 0xFFFF);
}
}
VOID
HalMiiInitIrqRtl8195a(
IN VOID *Data
)
{
PHAL_ETHER_ADAPTER pEthAdapter = (PHAL_ETHER_ADAPTER) Data;
PIRQ_HANDLE pMiiIrqHandle = &(pEthAdapter->IrqHandle);
if(pEthAdapter == NULL)
DBG_MII_ERR("pEthAdapter is NULL !!\n");
pMiiIrqHandle->Data = (u32) pEthAdapter;
pMiiIrqHandle->IrqNum = GMAC_IRQ;
pMiiIrqHandle->IrqFun = (IRQ_FUN) Mii_ISR;
pMiiIrqHandle->Priority = 6;
InterruptRegister(pMiiIrqHandle);
InterruptEn(pMiiIrqHandle);
}
static VOID
HalMiiDeInitIrqRtl8195a(
IN VOID *Data
)
{
PHAL_ETHER_ADAPTER pEthAdapter = (PHAL_ETHER_ADAPTER) Data;
IRQ_HANDLE MiiIrqHandle;
if(pEthAdapter == NULL)
DBG_8195A("pEthAdapter is NULL !!\n");
/* Clear all interrupt status */
HAL_MII_WRITE32(REG_MII_ISRIMR, ISR_CLR_ALL);
MiiIrqHandle.Data = (u32) pEthAdapter;
MiiIrqHandle.IrqNum = GMAC_IRQ;
MiiIrqHandle.IrqFun = (IRQ_FUN) Mii_ISR;
MiiIrqHandle.Priority = 6;
InterruptDis(&MiiIrqHandle);
InterruptUnRegister(&MiiIrqHandle);
}
#if 0
void Mii_DmaDone_ISR(u32 id)
{
isDmaDone = 1;
}
#endif
s32
HalMiiInitRtl8195a(
IN VOID
)
{
PHAL_ETHER_ADAPTER pEthAdapter = (PHAL_ETHER_ADAPTER)&HalEtherAdp;
u32 regVal = 0;
u8 macAddr[6];
u32 i = 0;
u16 ret;
if((!(pEthAdapter->tx_desc_num)) || (!(pEthAdapter->rx_desc_num)))
{
DBG_MII_ERR("Invalid Tx/Rx descriptor number !!\n");
return -1;
}
DBG_MII_INFO("Tx/Rx: %d/%d\n", pEthAdapter->tx_desc_num, pEthAdapter->rx_desc_num);
regVal = HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_PINMUX_CTRL);
regVal &= ~(BIT_EEPROM_PIN_EN);
HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_PINMUX_CTRL, regVal);
regVal = HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_PINMUX_CTRL);
regVal &= ~(BIT_SIC_PIN_EN);
HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_PINMUX_CTRL, regVal);
SPI_FLASH_PIN_FCTRL(OFF);
ACTCK_GPIO_CCTRL(ON);
SLPCK_GPIO_CCTRL(ON);
HAL_PERI_ON_WRITE32(REG_GPIO_SHTDN_CTRL, 0x7FF);
GPIO_FCTRL(ON);
/* 1. enable MII Pinmux & disable SDIO Host/Device mode Pinmux */
regVal = HAL_READ32(PERI_ON_BASE, REG_HCI_PINMUX_CTRL);
regVal |= BIT24;
regVal &= ~(BIT0 | BIT1); // Important!
HAL_WRITE32(PERI_ON_BASE, REG_HCI_PINMUX_CTRL, regVal);
/* 2. enable MII IP block (214, 12) */
regVal = HAL_READ32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN);
regVal |= BIT12;
HAL_WRITE32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN, regVal);
/* 3. Lexra2AHB Function Enable (304, 11) */
regVal = HAL_READ32(PERI_ON_BASE, REG_PESOC_SOC_CTRL);
regVal |= BIT11;
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_SOC_CTRL, regVal);
/* 4. enable MII bus clock (240, 24|25) */
regVal = HAL_READ32(PERI_ON_BASE, REG_PESOC_HCI_CLK_CTRL0);
regVal |= (BIT24 | BIT25);
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_HCI_CLK_CTRL0, regVal);
/* 5. */
regVal = HAL_READ32(SYSTEM_CTRL_BASE, 0x74) & 0xFFFFC7FF;
HAL_WRITE32(SYSTEM_CTRL_BASE, 0x74, (regVal | 0x00003000));
/* 6. AHB mux: select MII (214, 13) */
regVal = HAL_READ32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN);
regVal |= BIT13;
HAL_WRITE32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN, regVal);
/* 7. Vendor Register Clock Enable (230, 6|7) */
regVal = HAL_READ32(PERI_ON_BASE, REG_PESOC_CLK_CTRL);
regVal |= (BIT6 | BIT7);
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_CLK_CTRL, regVal);
/* 8. Enable GMAC Lexra Timeout (090, 16|17|18) */
regVal = HAL_READ32(VENDOR_REG_BASE, 0x0090);
regVal |= (BIT16 | BIT17 | BIT18);
HAL_WRITE32(VENDOR_REG_BASE, 0x0090, regVal);
/* 9. Endian Swap Control (304, 12|13) */
regVal = HAL_READ32(PERI_ON_BASE, REG_PESOC_SOC_CTRL);
regVal |= (BIT12 | BIT13);
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_SOC_CTRL, regVal);
HAL_MII_WRITE32(REG_MII_COM, (HAL_MII_READ32(REG_MII_COM) | COM_RST));
/* Tx settings */
HAL_MII_WRITE32(REG_MII_TC, ((TC_IFG_TIME << 10) & TC_IFG_MASK) | ((TC_NORMAL_MODE << 8) & TC_LBK_MASK)); // Normal mode
/* Rx settings */
HalMiiGetMacAddressRtl8195a(macAddr);
HAL_MII_WRITE32(REG_MII_IDR0, (macAddr[0] << 24) | (macAddr[1] << 16) | (macAddr[2] << 8) | macAddr[3]);
HAL_MII_WRITE32(REG_MII_IDR4, (macAddr[4] << 24) | (macAddr[5] << 16));
HAL_MII_WRITE32(REG_MII_RC, RC_AER | RC_AR | RC_AB | RC_AM | RC_APM | RC_AAP); // Accept error/runt/broadcast/multicast, etc.
HAL_MII_WRITE32(REG_MII_COM, (HAL_MII_READ32(REG_MII_COM) | COM_RXJUMBO)); // Support jumbo packet receiving
HAL_MII_WRITE32(REG_MII_ETNRXCPU1, 0x01010100);
TxDesc = (PTX_DESC_FMT)(pEthAdapter->TxDescAddr);
RxDesc = (PRX_DESC_FMT)(pEthAdapter->RxDescAddr);
if((TxDesc == NULL) || (RxDesc == NULL))
{
DBG_MII_ERR("Invalid Tx/Rx descriptor address !!\n");
return -1;
}
HAL_MII_WRITE32(REG_MII_TXFDP1, (u32)TxDesc);
HAL_MII_WRITE32(REG_MII_RXFDP1, (u32)RxDesc);
HAL_MII_WRITE32(REG_MII_IOCMD1, ((IOCMD1_DSC_FMT_EXTRA << 28) & IOCMD1_DSCFMTEXTRA_MASK) |
IOCMD1_EN_1GB); // Extra desc. format = 011, support 1GB addressing
HAL_MII_WRITE32(REG_MII_IOCMD, IOCMD_SHORT_DES_FMT |
((IOCMD_TXFTH_256 << 19) & IOCMD_TXFTH_MASK) |
((IOCMD_RXFTH_256 << 11) & IOCMD_RXFTH_MASK) |
IOCMD_TE); // short desc. format = 1, Tx & Rx FIFO threshold = 256 bytes, enable MII Tx
/* Reset PHY */
ret = HalMiiRwPhyRegRtl8195a(1, 0, PHY_SW_RESET);
while(1)
{
/* Check the reset status */
ret = HalMiiRwPhyRegRtl8195a(0, 0, 0);
if(!(ret & PHY_SW_RESET))
break;
}
/* Auto-Negotiation */
HalMiiForceLinkRtl8195a(-1, -1);
HalMiiInitIrqRtl8195a((VOID*)(&HalEtherAdp));
HAL_WRITE32(0xE000E100, 0x0, 0x00040000); // enable external interrupt[18] (GMAC)
/* ISR & IMR */
HalEtherAdp.InterruptMask = IMR_LINKCHG | IMR_TXOK | IMR_RER_OVF | IMR_RXOK | ISR_CLR_ALL;
HAL_MII_WRITE32(REG_MII_ISRIMR, HalEtherAdp.InterruptMask);
#if 0
/* Init GDMA */
gdmaObj.GdmaIrqHandle.IrqFun = (IRQ_FUN)Mii_DmaDone_ISR;
gdmaObj.GdmaIrqHandle.Data = (u32)(&gdmaObj);
isGdmaAllocated = HalGdmaMemCpyInit(&gdmaObj);
#endif
pTxDataBuf = pEthAdapter->pTxPktBuf;
pRxDataBuf = pEthAdapter->pRxPktBuf;
if((pTxDataBuf == NULL) || (pRxDataBuf == NULL))
{
DBG_MII_ERR("Invalid Tx/Rx packet buffer address !!\n");
return -1;
}
/* Fill Tx descriptors */
for(i = 0; i < (pEthAdapter->tx_desc_num); i++)
{
if(i == ((pEthAdapter->tx_desc_num) - 1))
TxDesc[i].dw1 = TX_DESC_EOR;
TxDesc[i].addr = (u32)(pTxDataBuf + (i * MII_BUF_SIZE));
TxDesc[i].dw2 = ((TX_DESC_VLAN_REMOVE << 25) & TX_DESC_VLAN_ACT_MASK) | (C_VLAN_HDR & TX_DESC_VLAN_TAG_MASK);
TxDesc[i].dw3 = 0;
TxDesc[i].dw4 = 0;
}
/* Fill Rx descriptors */
for(i = 0; i < (pEthAdapter->rx_desc_num); i++)
{
if(i == ((pEthAdapter->rx_desc_num) - 1))
RxDesc[i].dw1 = RX_DESC_OWN | RX_DESC_EOR | MII_BUF_SIZE;
else
RxDesc[i].dw1 = RX_DESC_OWN | MII_BUF_SIZE;
RxDesc[i].addr = (u32)(pRxDataBuf + (i * MII_BUF_SIZE));
RxDesc[i].dw2 = 0;
RxDesc[i].dw3 = 0;
}
#if 0
// Reset flag
TxDescIdx = 0;
TxBufIdx = 0;
isTxDone = 0;
CurrDataLen = 0;
CurrSentSize = 0;
RxDescIdx = 0;
RxBufIdx = 0;
isRxDone = 0;
CurrReceivedSize = 0;
ReadBufIdx = 0;
#endif
HAL_MII_WRITE32(REG_MII_IOCMD, (HAL_MII_READ32(REG_MII_IOCMD) | IOCMD_RE)); // enable MII Rx
HalDelayUs(1000);
DBG_8195A("Initialization is finished...\n");
return 0;
}
VOID
HalMiiDeInitRtl8195a(
IN VOID
)
{
#if 0
if (isGdmaAllocated)
HalGdmaMemCpyDeInit(&gdmaObj);
#endif
HalMiiDeInitIrqRtl8195a((VOID*)(&HalEtherAdp));
HAL_WRITE32(0xE000E100, 0x0, (HAL_READ32(0xE000E100, 0x0) & (~BIT18))); // disable external interrupt[18] (GMAC)
ACTCK_MII_MPHY_CCTRL(OFF);
SLPCK_MII_MPHY_CCTRL(OFF);
PinCtrl(MII, 0, OFF);
MII_FCTRL(OFF);
}
s32
HalMiiWriteDataRtl8195a(
IN const char *Data,
IN u32 Size
)
{
PHAL_ETHER_ADAPTER pEthAdapter = (PHAL_ETHER_ADAPTER)&HalEtherAdp ;
if((Data == NULL) || (Size == 0) || (Size > MAX_FRAME_SIZE))
{
DBG_MII_ERR("Invalid parameter !!\n");
return -1;
}
/* Check if current Tx descriptor is available */
u8 tx_serach_idx = TxDescWrPtr;
if((((volatile u32)TxDesc[tx_serach_idx].dw1) & TX_DESC_OWN) == 0)
{
#if 1
_memcpy((void*)(TxDesc[tx_serach_idx].addr), Data, Size);
#else
isDmaDone = 0;
HalGdmaMemCpy(&gdmaObj, (void*)(TxDesc[tx_serach_idx].addr), (void*)Data, Size);
while (isDmaDone == 0);
#endif
TxDesc[tx_serach_idx].dw1 &= TX_DESC_EOR; // keep the EOR bit
TxDesc[tx_serach_idx].dw1 |= TX_DESC_OWN | TX_DESC_FS | TX_DESC_LS | TX_DESC_CRC | Size;
TxDesc[tx_serach_idx].dw2 = ((TX_DESC_VLAN_REMOVE << 25) & TX_DESC_VLAN_ACT_MASK) | (C_VLAN_HDR & TX_DESC_VLAN_TAG_MASK);
CurrDataLen += Size;
}
else
{
/* Enable TxOK interrupt */
HalEtherAdp.InterruptMask |= IMR_TXOK;
HAL_MII_WRITE32(REG_MII_ISRIMR, HalEtherAdp.InterruptMask);
/* Enable Tx ring1 */
HAL_MII_WRITE32(REG_MII_IOCMD, (HAL_MII_READ32(REG_MII_IOCMD) | IOCMD_TXFN1ST));
DBG_MII_WARN("Tx ring full\n");
/* Upper layer will re-transmit this packet */
return 0;
}
/* Check if reach to the end of the ring */
if(tx_serach_idx == ((pEthAdapter->tx_desc_num) - 1))
TxDescWrPtr = 0;
else
TxDescWrPtr++;
return Size;
}
u32
HalMiiSendPacketRtl8195a(
IN VOID
)
{
u32 size = CurrDataLen;
/* Enable TxOK interrupt */
HalEtherAdp.InterruptMask |= IMR_TXOK;
HAL_MII_WRITE32(REG_MII_ISRIMR, HalEtherAdp.InterruptMask);
/* Enable Tx ring1 */
HAL_MII_WRITE32(REG_MII_IOCMD, (HAL_MII_READ32(REG_MII_IOCMD) | IOCMD_TXFN1ST));
CurrDataLen = 0;
return size;
}
u32
HalMiiReceivePacketRtl8195a(
IN VOID
)
{
u8 rx_serach_idx = RxDescRdPtr;
u32 rx_len = 0;
/* Check if Rx descriptor is available */
if((((volatile u32)RxDesc[rx_serach_idx].dw1) & RX_DESC_OWN) == 0)
{
rx_len = (RxDesc[rx_serach_idx].dw1) & RX_DESC_DATA_LEN_MASK;
}
else
{
/* Enable interrupt again */
DBG_MII_INFO("RX ring empty\n\r");
HalEtherAdp.InterruptMask |= (IMR_RXOK | ISR_RER_OVF);
HAL_MII_WRITE32(REG_MII_ISRIMR, HalEtherAdp.InterruptMask);
return 0;
}
return rx_len;
}
u32
HalMiiReadDataRtl8195a(
IN u8 *Data,
IN u32 Size
)
{
PHAL_ETHER_ADAPTER pEthAdapter = (PHAL_ETHER_ADAPTER)&HalEtherAdp;
u32 read_idx = RxDescRdPtr;
if((Data == NULL) || (Size == 0) || (Size > 1518))
{
DBG_MII_ERR("Wrong params\n");
return 0;
}
#if 1
_memcpy((void*)Data, (void*)(RxDesc[read_idx].addr + 2), Size);
#else
isDmaDone = 0;
HalGdmaMemCpy(&gdmaObj, (void*)Data, (void*)(RxDesc[read_idx].addr + 2), Size);
while (isDmaDone == 0);
#endif
RxDesc[read_idx].dw1 &= RX_DESC_EOR; // keep the EOR bit
RxDesc[read_idx].dw1 |= (RX_DESC_OWN | MII_BUF_SIZE);
//RxDesc[read_idx].addr = (u32)(pRxDataBuf + (read_idx * MII_BUF_SIZE));
RxDesc[read_idx].dw2 = 0;
RxDesc[read_idx].dw3 = 0;
/* Update the read pointer */
if(read_idx == ((pEthAdapter->rx_desc_num) - 1))
RxDescRdPtr = 0;
else
RxDescRdPtr++;
return Size;
}
VOID
HalMiiGetMacAddressRtl8195a(
IN u8 *Addr
)
{
u8 *ptr;
// To do: Get info. from Flash or Efuse
ptr = Addr;
*(ptr) = 0x12;
*(ptr+1) = 0x34;
*(ptr+2) = 0x56;
*(ptr+3) = 0x78;
*(ptr+4) = 0x9A;
*(ptr+5) = 0xBC;
}
u32
HalMiiGetLinkStatusRtl8195a(
IN VOID
)
{
u32 ret;
if(HAL_MII_READ32(REG_MII_MS) & MS_LINKB)
ret = 0; // Link down
else
ret = 1; // Link up
return ret;
}
#if 0
VOID
HalMiiForceLinkRtl8195a(
IN s32 Speed,
IN s32 Duplex
)
{
u32 regVal = 0;
u16 ret;
#if 0
/* Reset PHY */
HAL_MII_WRITE32(REG_MII_MIIA, MIIA_FLAG |
((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) |
((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK) |
PHY_SW_RESET);
HalDelayUs(1000);
do {
}while(HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG);
while(1)
{
/* Check reset status */
HAL_MII_WRITE32(REG_MII_MIIA, ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK));
HalDelayUs(1000);
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
regVal = HAL_MII_READ32(REG_MII_MIIA) & 0xFFFF;
if(!(regVal & PHY_SW_RESET))
break;
}
DBG_MII_INFO("PHY reset is completed...\n");
#endif
/* Switch to Page 0 */
ret = HalMiiRwPhyRegRtl8195a(1, 31, 0);
if(((Speed == 1) && (Duplex == 1)) || ((Speed == 1) && (Duplex == 0)) || ((Speed == 0) && (Duplex == 1)) || ((Speed == 0) && (Duplex == 0)))
{
/* Disable Auto-negotiation */
HAL_MII_WRITE32(REG_MII_MIIA, MIIA_FLAG |
((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) |
((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK) |
0x0000);
HalDelayUs(1000);
do {
}while(HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG);
/* Manual settings */
HAL_MII_WRITE32(REG_MII_MIIA, MIIA_FLAG |
((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) |
((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK) |
(((Speed << 13) & PHY_SPEED_LSB) | ((Duplex << 8) & PHY_DUPLEX_MODE)));
HalDelayUs(1000);
do {
}while(HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG);
}
else
{
#if 1
/* Reset PHY */
HAL_MII_WRITE32(REG_MII_MIIA, MIIA_FLAG |
((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) |
((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK) |
PHY_SW_RESET);
HalDelayUs(1000);
do {
}while(HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG);
while(1)
{
/* Check reset status */
HAL_MII_WRITE32(REG_MII_MIIA, ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK));
HalDelayUs(1000);
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
regVal = HAL_MII_READ32(REG_MII_MIIA) & 0xFFFF;
if(!(regVal & PHY_SW_RESET))
break;
}
DBG_MII_INFO("PHY reset is completed...\n");
#endif
while(1)
{
/* Check Auto-negotiation process status */
HAL_MII_WRITE32(REG_MII_MIIA, ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((PHY_REG1_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK));
HalDelayUs(1000);
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
regVal = HAL_MII_READ32(REG_MII_MIIA) & 0xFFFF;
if(regVal & PHY_NWAY_COMPLETE)
break;
}
DBG_MII_INFO("Auto-negotiation is completed...\n");
}
/* Wait until link is up */
while(1)
{
HAL_MII_WRITE32(REG_MII_MIIA, ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((PHY_REG1_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK));
HalDelayUs(1000);
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
HalDelayUs(1000);
HAL_MII_WRITE32(REG_MII_MIIA, ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((PHY_REG1_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK));
HalDelayUs(1000);
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
regVal = HAL_MII_READ32(REG_MII_MIIA) & 0xFFFF;
if(regVal & PHY_LINK_STATUS)
break;
}
/* Get link info. */
HAL_MII_WRITE32(REG_MII_MIIA, ((PHY_ADDRESS << 26) & MIIA_PHY_ADDR_MASK) | ((PHY_REG0_ADDR << 16) & MIIA_PHY_REG_ADDR_MASK));
HalDelayUs(1000);
do {
}while((HAL_MII_READ32(REG_MII_MIIA) & MIIA_FLAG) == 0);
regVal = HAL_MII_READ32(REG_MII_MIIA) & 0xFFFF;
if((!(regVal & PHY_SPEED_MSB)) && (regVal & PHY_SPEED_LSB))
{
if(regVal & PHY_DUPLEX_MODE)
DBG_8195A("Link status: 100 Mb/s, Full duplex\n");
else
DBG_8195A("Link status: 100 Mb/s, Half duplex\n");
}
else if((!(regVal & PHY_SPEED_MSB)) && (!(regVal & PHY_SPEED_LSB)))
{
if(regVal & PHY_DUPLEX_MODE)
DBG_8195A("Link status: 10 Mb/s, Full duplex\n");
else
DBG_8195A("Link status: 10 Mb/s, Half duplex\n");
}
HalDelayUs(4000000);
}
#else
VOID
HalMiiForceLinkRtl8195a(
IN s32 Speed,
IN s32 Duplex
)
{
u16 ret;
/* Switch to Page 0 */
ret = HalMiiRwPhyRegRtl8195a(1, 31, 0);
if(((Speed == 1) && (Duplex == 1)) || ((Speed == 1) && (Duplex == 0)) || ((Speed == 0) && (Duplex == 1)) || ((Speed == 0) && (Duplex == 0)))
{
/* Disable Auto-negotiation */
ret = HalMiiRwPhyRegRtl8195a(1, 0, 0x0);
/* Manual settings */
ret = HalMiiRwPhyRegRtl8195a(1, 0, (((Speed << 13) & PHY_SPEED_LSB) | ((Duplex << 8) & PHY_DUPLEX_MODE)));
}
else
{
/* Restart Auto-negotiation */
ret = HalMiiRwPhyRegRtl8195a(1, 0, PHY_NWAY_EN | PHY_RESTART_NWAY);
while(1)
{
/* Check the reset status */
ret = HalMiiRwPhyRegRtl8195a(0, 0, 0);
if(!(ret & PHY_RESTART_NWAY))
break;
}
/* Check Auto-negotiation process status */
while(1)
{
ret = HalMiiRwPhyRegRtl8195a(0, 1, 0);
if(ret & PHY_NWAY_COMPLETE)
break;
}
DBG_MII_INFO("Auto-negotiation is completed...\n");
}
/* Wait until link is up */
while(1)
{
ret = HalMiiRwPhyRegRtl8195a(0, 1, 0);
HalDelayUs(1000);
ret = HalMiiRwPhyRegRtl8195a(0, 1, 0);
if(ret & PHY_LINK_STATUS)
break;
}
/* Get link info. */
ret = HalMiiRwPhyRegRtl8195a(0, 0, 0);
if((!(ret & PHY_SPEED_MSB)) && (ret & PHY_SPEED_LSB))
{
if(ret & PHY_DUPLEX_MODE)
DBG_8195A("Link status: 100 Mb/s, Full duplex\n");
else
DBG_8195A("Link status: 100 Mb/s, Half duplex\n");
}
else if((!(ret & PHY_SPEED_MSB)) && (!(ret & PHY_SPEED_LSB)))
{
if(ret & PHY_DUPLEX_MODE)
DBG_8195A("Link status: 10 Mb/s, Full duplex\n");
else
DBG_8195A("Link status: 10 Mb/s, Half duplex\n");
}
HalDelayUs(4000000);
}
#endif
#ifdef CONFIG_MII_VERIFY
VOID MiiIrqHandle (IN VOID *Data);
VOID MiiIrqHandle (IN VOID *Data) {
u32 RegValue = HalMiiGmacGetInterruptStatusRtl8195a();
extern volatile u8 isRxOK;
extern volatile u8 isTxOK;
extern volatile u8 RxIntCnt;
// DBG_8195A("ISR = 0x%08X\n", RegValue);
if(RegValue & GMAC_ISR_ROK) {
HalMiiGmacClearInterruptStatusRtl8195a(0x00410001);
isRxOK = 1;
RxIntCnt++;
}
if(RegValue & GMAC_ISR_TOK_TI) {
HalMiiGmacClearInterruptStatusRtl8195a(0x00410040);
isTxOK = 1;
}
}
/**
* MII Initialize.
*
* MII Initialize.
*
* Initialization Steps:
* I. Rtl8195A Board Configurations:
* 1. MII Function Enable & AHB mux
*
* @return runtime status value.
*/
BOOL
HalMiiGmacInitRtl8195a(
IN VOID *Data
)
{
u32 RegValue;
/* 1. enable MII Pinmux & disable SDIO Host/Device mode Pinmux */
RegValue = HAL_READ32(PERI_ON_BASE, REG_HCI_PINMUX_CTRL);
RegValue |= BIT24;
RegValue &= ~(BIT0 | BIT1); // Important!
HAL_WRITE32(PERI_ON_BASE, REG_HCI_PINMUX_CTRL, RegValue);
/* 2. enable MII IP block (214, 12) */
RegValue = HAL_READ32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN);
RegValue |= BIT12;
HAL_WRITE32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN, RegValue);
/* 3. Lexra2AHB Function Enable (304, 11) */
RegValue = HAL_READ32(PERI_ON_BASE, REG_PESOC_SOC_CTRL);
RegValue |= BIT11;
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_SOC_CTRL, RegValue);
/* 4. enable MII bus clock (240, 24|25) */
RegValue = HAL_READ32(PERI_ON_BASE, REG_PESOC_HCI_CLK_CTRL0);
RegValue |= (BIT24 | BIT25);
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_HCI_CLK_CTRL0, RegValue);
/* 5. */
RegValue = HAL_READ32(SYSTEM_CTRL_BASE, 0x74) & 0xFFFFC7FF;
HAL_WRITE32(SYSTEM_CTRL_BASE, 0x74, (RegValue | 0x00003000));
/* 6. AHB mux: select MII (214, 13) */
RegValue = HAL_READ32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN);
RegValue |= BIT13;
HAL_WRITE32(PERI_ON_BASE, REG_SOC_HCI_COM_FUNC_EN, RegValue);
/* 7. Vendor Register Clock Enable (230, 6|7) */
RegValue = HAL_READ32(PERI_ON_BASE, REG_PESOC_CLK_CTRL);
RegValue |= (BIT6 | BIT7);
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_CLK_CTRL, RegValue);
/* 8. Enable GMAC Lexra Timeout (090, 16|17|18) */
RegValue = HAL_READ32(VENDOR_REG_BASE, 0x0090);
RegValue |= (BIT16 | BIT17 | BIT18);
HAL_WRITE32(VENDOR_REG_BASE, 0x0090, RegValue);
/* 9. Endian Swap Control (304, 12|13) */
RegValue = HAL_READ32(PERI_ON_BASE, REG_PESOC_SOC_CTRL);
RegValue |= (BIT12 | BIT13);
HAL_WRITE32(PERI_ON_BASE, REG_PESOC_SOC_CTRL, RegValue);
return _TRUE;
}
BOOL
HalMiiGmacResetRtl8195a(
IN VOID *Data
)
{
HAL_MII_WRITE32(REG_RTL_MII_CR, (HAL_MII_READ32(REG_RTL_MII_CR) | BIT0));
return _TRUE;
}
BOOL
HalMiiGmacEnablePhyModeRtl8195a(
IN VOID *Data
)
{
return _TRUE;
}
u32
HalMiiGmacXmitRtl8195a(
IN VOID *Data
)
{
return 0;
}
VOID
HalMiiGmacCleanTxRingRtl8195a(
IN VOID *Data
)
{
}
VOID
HalMiiGmacFillTxInfoRtl8195a(
IN VOID *Data
)
{
PMII_ADAPTER pMiiAdapter = (PMII_ADAPTER) Data;
PTX_INFO pTx_Info = pMiiAdapter->pTx_Info;
VOID* TxBuffer = pMiiAdapter->TxBuffer;
pTx_Info->opts1.dw = 0xBC8001FE;
/* pTx_Info->opts1.dw = 0xBC800080; // size: 128 */
pTx_Info->addr = (u32)TxBuffer;
pTx_Info->opts2.dw = 0x0400279F;
pTx_Info->opts3.dw = 0x00000000;
/* pTx_Info->opts4.dw = 0x57800000; */
pTx_Info->opts4.dw = 0x1FE00000;
HAL_MII_WRITE32(REG_RTL_MII_TXFDP1, pTx_Info);
}
VOID
HalMiiGmacFillRxInfoRtl8195a(
IN VOID *Data
)
{
PMII_ADAPTER pMiiAdapter = (PMII_ADAPTER) Data;
PRX_INFO pRx_Info = pMiiAdapter->pRx_Info;
VOID* RxBuffer = pMiiAdapter->RxBuffer;
/* pRx_Info->opts1.dw = 0x80000200; //Data Length: 4095(FFF), 512(200) */
pRx_Info->opts1.dw = 0x800001FC; //Data Length: 4095(FFF), 512(200)
/* pRx_Info->opts1.dw = 0x8000007F; */
pRx_Info->addr = (u32)RxBuffer;
pRx_Info->opts2.dw = 0x00000000;
pRx_Info->opts3.dw = 0x00000000;
HAL_MII_WRITE32(REG_RTL_MII_RXFDP1, pRx_Info);
}
VOID
HalMiiGmacTxRtl8195a(
IN VOID *Data
)
{
u32 RegValue;
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD);
RegValue |= BIT_IOCMD_TXENABLE(1);
HAL_MII_WRITE32(REG_RTL_MII_IOCMD, RegValue);
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD);
RegValue |= BIT_IOCMD_FIRST_DMATX_ENABLE(1);
HAL_MII_WRITE32(REG_RTL_MII_IOCMD, RegValue);
}
VOID
HalMiiGmacRxRtl8195a(
IN VOID *Data
)
{
u32 RegValue;
RegValue = HAL_MII_READ32(REG_RTL_MII_TCR);
HAL_MII_WRITE32(REG_RTL_MII_TCR, 0x00000D00); // loopback R2T mode
RegValue = HAL_MII_READ32(REG_RTL_MII_RCR);
HAL_MII_WRITE32(REG_RTL_MII_RCR, 0x0000007F);
RegValue = HAL_MII_READ32(REG_RTL_MII_ETNRXCPU1);
HAL_MII_WRITE32(REG_RTL_MII_ETNRXCPU1, 0x1F0A0F00);
RegValue = HAL_MII_READ32(REG_RTL_MII_RX_PSE1);
HAL_MII_WRITE32(REG_RTL_MII_RX_PSE1, 0x00000022);
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD1);
RegValue |= BIT_IOCMD1_FIRST_DMARX_ENABLE(1);
HAL_MII_WRITE32(REG_RTL_MII_IOCMD1, RegValue);
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD);
RegValue |= BIT_IOCMD_RXENABLE(1);
HAL_MII_WRITE32(REG_RTL_MII_IOCMD, RegValue);
}
VOID
HalMiiGmacSetDefaultEthIoCmdRtl8195a(
IN VOID *Data
)
{
u32 RegValue;
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD);
HAL_MII_WRITE32(REG_RTL_MII_IOCMD, CMD_CONFIG);
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD1);
HAL_MII_WRITE32(REG_RTL_MII_IOCMD1, CMD1_CONFIG);
//2014-04-29 yclin (disable 0x40051438[27] r_en_precise_dma) {
RegValue = HAL_MII_READ32(REG_RTL_MII_IOCMD1);
RegValue = RegValue & 0xF7FFFFFF;
HAL_MII_WRITE32(REG_RTL_MII_IOCMD1, RegValue);
// }
}
VOID
HalMiiGmacInitIrqRtl8195a(
IN VOID *Data
)
{
IRQ_HANDLE MiiIrqHandle_Master;
PMII_ADAPTER pMiiAdapter = (PMII_ADAPTER) Data;
MiiIrqHandle_Master.Data = (u32) (pMiiAdapter);
MiiIrqHandle_Master.IrqNum = GMAC_IRQ;
MiiIrqHandle_Master.IrqFun = (IRQ_FUN) MiiIrqHandle;
MiiIrqHandle_Master.Priority = 10;
InterruptRegister(&MiiIrqHandle_Master);
InterruptEn(&MiiIrqHandle_Master);
}
u32
HalMiiGmacGetInterruptStatusRtl8195a(
VOID
)
{
u32 RegValue;
RegValue = HAL_MII_READ32(REG_RTL_MII_IMRISR);
return RegValue;
}
VOID
HalMiiGmacClearInterruptStatusRtl8195a(
u32 IsrStatus
)
{
HAL_MII_WRITE32(REG_RTL_MII_IMRISR, IsrStatus);
}
#endif // #ifdef CONFIG_MII_VERIFY