blob: 2b2f6edb1fa057340b1015f45ecb6dd59f06c2b0 [file] [log] [blame]
/*
* drivers/net/arasan_emac_ahb.h
*
* Copyright (c) Quantenna Communications Incorporated 2007.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __COMMON_RUBY_ARASAN_EMAC_AHB_H
#define __COMMON_RUBY_ARASAN_EMAC_AHB_H 1
#ifdef TOPAZ_AMBER_IP
#include <qtn/amber.h>
#endif
extern __inline__ void __mydelay(unsigned long loops)
{
__asm__ __volatile__ ( "1: \n\t"
"sub.f %0, %1, 1\n\t"
"jpnz 1b"
: "=r" (loops)
: "0" (loops));
}
/*
* Division by multiplication: you don't have to worry about loss of
* precision.
*
* Use only for very small delays ( < 1 msec). Should probably use a
* lookup table, really, as the multiplications take much too long with
* short delays. This is a "reasonable" implementation, though (and the
* first constant multiplications gets optimized away if the delay is
* a constant)
*/
static inline void __const_myudelay(unsigned long xloops)
{
__asm__ ("mpyhu %0, %1, %2"
: "=r" (xloops)
: "r" (xloops), "r" (1<<20)); /* Number derived from loops per jiffy */
__mydelay(xloops * 100); /* Jiffies per sec */
}
static inline void __myudelay(unsigned long usecs)
{
__const_myudelay(usecs * 4295); /* 2**32 / 1000000 */
}
#ifndef MAX_UDELAY_MS
#define MAX_UDELAY_MS 5
#endif
#ifndef mydelay
#define mydelay(n) (\
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? __myudelay((n)*1000) : \
({unsigned long __ms=(n); while (__ms--) __myudelay(1000);}))
#endif
#define DELAY_40MILLISEC (40)
#define DELAY_50MILLISEC (50)
/* Arasan Gigabit AHB controller register offsets */
#define EMAC_DMA_CONFIG 0x0000
#define EMAC_DMA_CTRL 0x0004
#define EMAC_DMA_STATUS_IRQ 0x0008
#define EMAC_DMA_INT_ENABLE 0x000C
#define EMAC_DMA_TX_AUTO_POLL 0x0010
#define EMAC_DMA_TX_POLL_DEMAND 0x0014
#define EMAC_DMA_RX_POLL_DEMAND 0x0018
#define EMAC_DMA_TX_BASE_ADDR 0x001C
#define EMAC_DMA_RX_BASE_ADDR 0x0020
#define EMAC_DMA_MISSED_FRAMES 0x0024
#define EMAC_DMA_STOP_FLUSHES 0x0028
#define EMAC_DMA_RX_IRQ_MITIGATION 0x002C
#define EMAC_DMA_CUR_TXDESC_PTR 0x0030
#define EMAC_DMA_CUR_TXBUF_PTR 0x0034
#define EMAC_DMA_CUR_RXDESC_PTR 0x0038
#define EMAC_DMA_CUR_RXBUF_PTR 0x003C
#define EMAC_MAC_GLOBAL_CTRL 0x0100
#define EMAC_MAC_TX_CTRL 0x0104
#define EMAC_MAC_RX_CTRL 0x0108
#define EMAC_MAC_MAX_FRAME_SIZE 0x010C
#define EMAC_MAC_TX_JABBER_SIZE 0x0110
#define EMAC_MAC_RX_JABBER_SIZE 0x0114
#define EMAC_MAC_ADDR_CTRL 0x0118
#define EMAC_MAC_ADDR1_HIGH 0x0120
#define EMAC_MAC_ADDR1_MED 0x0124
#define EMAC_MAC_ADDR1_LOW 0x0128
#define EMAC_MAC_ADDR2_HIGH 0x012C
#define EMAC_MAC_ADDR2_MED 0x0130
#define EMAC_MAC_ADDR2_LOW 0x0134
#define EMAC_MAC_ADDR3_HIGH 0x0138
#define EMAC_MAC_ADDR3_MED 0x013C
#define EMAC_MAC_ADDR3_LOW 0x0140
#define EMAC_MAC_ADDR4_HIGH 0x0144
#define EMAC_MAC_ADDR4_MED 0x0148
#define EMAC_MAC_ADDR4_LOW 0x014C
#define EMAC_MAC_TABLE1 0x0150
#define EMAC_MAC_TABLE2 0x0154
#define EMAC_MAC_TABLE3 0x0158
#define EMAC_MAC_TABLE4 0x015C
#define EMAC_MAC_FLOW_CTRL 0x0160
#define EMAC_MAC_FLOW_PAUSE_GENERATE 0x0164
#define EMAC_MAC_FLOW_SA_HIGH 0x0168
#define EMAC_MAC_FLOW_SA_MED 0x016C
#define EMAC_MAC_FLOW_SA_LOW 0x0170
#define EMAC_MAC_FLOW_DA_HIGH 0x0174
#define EMAC_MAC_FLOW_DA_MED 0x0178
#define EMAC_MAC_FLOW_DA_LOW 0x017C
#define EMAC_MAC_FLOW_PAUSE_TIMEVAL 0x0180
#define EMAC_MAC_MDIO_CTRL 0x01A0
#define EMAC_MAC_MDIO_DATA 0x01A4
#define EMAC_MAC_RXSTAT_CTRL 0x01A8
#define EMAC_MAC_RXSTAT_DATA_HIGH 0x01AC
#define EMAC_MAC_RXSTAT_DATA_LOW 0x01B0
#define EMAC_MAC_TXSTAT_CTRL 0x01B4
#define EMAC_MAC_TXSTAT_DATA_HIGH 0x01B8
#define EMAC_MAC_TXSTAT_DATA_LOW 0x01BC
#define EMAC_MAC_TX_ALMOST_FULL 0x01C0
#define EMAC_MAC_TX_START_THRESHOLD 0x01C4
#define EMAC_MAC_RX_START_THRESHOLD 0x01C8
#define EMAC_MAC_INT 0x01E0
#define EMAC_MAC_INT_ENABLE 0x01E4
#ifndef __ASSEMBLY__
/* Common structure for tx and rx descriptors */
struct emac_desc {
volatile u32 status;
volatile u32 control;
volatile u32 bufaddr1;
volatile u32 bufaddr2;
};
enum DmaRxDesc {
/* status field */
RxDescOwn = (1 << 31),
RxDescFirstDesc = (1 << 30),
RxDescLastDesc = (1 << 29),
RxDescStatusLenErr = (1 << 23),
RxDescStatusJabberErr = (1 << 22),
RxDescStatusMaxLenErr = (1 << 21),
RxDescStatusCRCErr = (1 << 20),
RxDescStatusRuntFrame = (1 << 15),
RxDescStatusAlignErr = (1 << 14),
RxDescStatusShift = 14,
RxDescStatusMask = 0x7fff,
RxDescFrameLenShift = 0,
RxDescFrameLenMask = 0x3fff,
/* control field */
RxDescEndOfRing = (1 << 26),
RxDescChain2ndAddr = (1 << 25),
RxDescBuf2SizeShift = 12,
RxDescBuf2SizeMask = 0xfff,
RxDescBuf1SizeShift = 0,
RxDescBuf1SizeMask = 0xfff,
};
enum DmaTxDesc {
/* status field */
TxDescOwn = (1 << 31),
TxDescStatusShift = 0,
TxDescStatusMask = 0x8fffffff,
/* control field */
TxDescIntOnComplete = (1 << 31),
TxDescLastSeg = (1 << 30),
TxDescFirstSeg = (1 << 29),
TxDescCrcDisable = (1 << 28),
TxDescPadDisable = (1 << 27),
TxDescEndOfRing = (1 << 26),
TxDescChain2ndAddr = (1 << 25),
TxDescForceEopErr = (1 << 24),
TxDescBuf2SizeShift = 12,
TxDescBuf2SizeMask = 0xfff,
TxDescBuf1SizeShift = 0,
TxDescBuf1SizeMask = 0xfff,
};
enum AraMacRegVals {
/* DMA config register */
DmaSoftReset = 1,
Dma1WordBurst = (0x01 << 1),
Dma4WordBurst = (0x04 << 1),
Dma16WordBurst = (0x10 << 1),
DmaRoundRobin = (1 << 15),
DmaWait4Done = (1 << 16),
DmaStrictBurst = (1 << 17),
Dma64BitMode = (1 << 18),
/* DMA control register */
DmaStartTx = (1 << 0),
DmaStartRx = (1 << 1),
/* DMA status/interrupt & interrupt mask registers */
DmaTxDone = (1 << 0),
DmaNoTxDesc = (1 << 1),
DmaTxStopped = (1 << 2),
DmaRxDone = (1 << 4),
DmaNoRxDesc = (1 << 5),
DmaRxStopped = (1 << 6),
DmaRxMissedFrame = (1 << 7),
DmaMacInterrupt = (1 << 8),
DmaAllInts = DmaTxDone | DmaNoTxDesc | DmaTxStopped | DmaRxDone |
DmaNoRxDesc | DmaRxStopped | DmaRxMissedFrame | DmaMacInterrupt,
DmaTxStateMask = (7 << 16),
DmaTxStateStopped = (0 << 16),
DmaTxStateFetchDesc = (1 << 16),
DmaTxStateFetchData = (2 << 16),
DmaTxStateWaitEOT = (3 << 16),
DmaTxStateCloseDesc = (4 << 16),
DmaTxStateSuspended = (5 << 16),
DmaRxStateMask = (15 << 21),
DmaRxStateStopped = (0 << 21),
DmaRxStateFetchDesc = (1 << 21),
DmaRxStateWaitEOR = (2 << 21),
DmaRxStateWaitFrame = (3 << 21),
DmaRxStateSuspended = (4 << 21),
DmaRxStateCloseDesc = (5 << 21),
DmaRxStateFlushBuf = (6 << 21),
DmaRxStatePutBuf = (7 << 21),
DmaRxStateWaitStatus = (8 << 21),
/* MAC global control register */
MacSpeed10M = (0 << 0),
MacSpeed100M = (1 << 0),
MacSpeed1G = (2 << 0),
MacSpeedMask = (3 << 0),
MacFullDuplex = (1 << 2),
MacResetRxStats = (1 << 3),
MacResetTxStats = (1 << 4),
/* MAC TX control */
MacTxEnable = (1 << 0),
MacTxInvertFCS = (1 << 1),
MacTxDisableFCSInsertion = (1 << 2),
MacTxAutoRetry = (1 << 3),
MacTxIFG96 = (0 << 4),
MacTxIFG64 = (1 << 4),
MacTxIFG128 = (2 << 4),
MacTxIFG256 = (3 << 4),
MacTxPreamble7 = (0 << 6),
MacTxPreamble3 = (2 << 6),
MacTxPreamble5 = (3 << 6),
/* MAC RX control */
MacRxEnable = (1 << 0),
MacRxStripFCS = (1 << 2),
MacRxStoreAndForward = (1 << 3),
MacAccountVLANs = (1 << 6),
/* MAC address control */
MacAddr1Enable = (1 << 0),
MacAddr2Enable = (1 << 1),
MacAddr3Enable = (1 << 2),
MacAddr4Enable = (1 << 3),
MacInverseAddr1Enable = (1 << 4),
MacInverseAddr2Enable = (1 << 5),
MacInverseAddr3Enable = (1 << 6),
MacInverseAddr4Enable = (1 << 7),
MacPromiscuous = (1 << 8),
/* MAC flow control */
MacFlowDecodeEnable = (1 << 0),
MacFlowGenerationEnable = (1 << 1),
MacAutoFlowGenerationEnable = (1 << 2),
MacFlowMulticastMode = (1 << 3),
MacBlockPauseFrames = (1 << 4),
/* MDIO control register values */
MacMdioCtrlPhyMask = 0x1f,
MacMdioCtrlPhyShift = 0,
MacMdioCtrlRegMask = 0x1f,
MacMdioCtrlRegShift = 5,
MacMdioCtrlRead = (1 << 10),
MacMdioCtrlWrite = 0,
MacMdioCtrlClkMask = 0x3,
MacMdioCtrlClkShift = 11,
MacMdioCtrlStart = (1 << 15),
/* MDIO data register values */
MacMdioDataMask = 0xffff,
/* MAC interrupt & interrupt mask values */
MacUnderrun = (1 << 0),
MacJabber = (1 << 0),
/* RX statistics counter control */
RxStatReadBusy = (1 << 15),
/* TX statistics counter control */
TxStatReadBusy = (1 << 15),
};
enum ArasanTxStatisticsCounters {
FramesSentOK = 0,
FramesSentTotal = 1,
OctetsSentOK = 2,
FramesSentError = 3,
FramesSentSingleCol = 4,
FramesSentMultipleCol = 5,
FramesSentLateCol = 6,
FramesSentExcessiveCol = 7,
FramesSentUnicast = 8,
FramesSentMulticast = 9,
FramesSentBroadcast = 10,
FramesSentPause = 11,
TxLastStatCounter = 11,
};
enum ArasanRxStatisticsCounters {
FramesRxOK = 0,
FramesRxTotal = 1,
FramesRxCrcErr = 2,
FramesRxAlignErr = 3,
FramesRxErrTotal = 4,
OctetsRxOK = 5,
OctetsRxTotal = 6,
FramesRxUnicast = 7,
FramesRxMulticast = 8,
FramesRxBroadcast = 9,
FramesRxPause = 10,
FramesRxLenErr = 11,
FramesRxUndersized = 12,
FramesRxOversized = 13,
FramesRxFragments = 14,
FramesRxJabber = 15,
FramesRx64bytes = 16,
FramesRx65to127bytes = 17,
FramesRx128to255bytes = 18,
FramesRx256to511bytes = 19,
FramesRx512to1023bytes = 20,
FramesRx1024to1518bytes = 21,
FramesRxOver1518bytes = 22,
FramesRxDroppedBufFull = 23,
FramesRxTruncatedBufFull = 24,
RxLastStatCounter = 24,
};
extern int mdc_clk_divisor;
static inline void arasan_initialize_release_reset(uint32_t emac0_cfg,
uint32_t emac1_cfg, uint32_t rgmii_timing, uint32_t ext_reset)
{
uint32_t emac_cfg = emac0_cfg | emac1_cfg;
unsigned long reset_mask;
uint32_t mii_value = 0x481 | ((mdc_clk_divisor & MacMdioCtrlClkMask) << MacMdioCtrlClkShift);
if (!(emac_cfg & EMAC_IN_USE)) {
return;
}
/* both interfaces (if enabled) must use same mii config so we can just or here */
writel(RUBY_SYS_CTL_MASK_MII, RUBY_SYS_CTL_MASK);
if (emac0_cfg & EMAC_PHY_MII) {
writel(RUBY_SYS_CTL_MASK_MII_EMAC0, RUBY_SYS_CTL_CTRL);
}
if (emac1_cfg & EMAC_PHY_MII) {
writel(RUBY_SYS_CTL_MASK_MII_EMAC1, RUBY_SYS_CTL_CTRL);
}
if (!(emac0_cfg & EMAC_PHY_MII) && !(emac1_cfg & EMAC_PHY_MII)){
writel(0, RUBY_SYS_CTL_CTRL);
}
/* Have PLL clock signal go out */
writel_topaz(TOPAZ_SYS_CTL_PLLCLKOUT_EN, RUBY_SYS_CTL_MASK);
writel_topaz(TOPAZ_SYS_CTL_PLLCLKOUT_EN, RUBY_SYS_CTL_CTRL);
/*
* if RGMII mode, we need to configure the clock before we release reset and also
* make sure we actually reset the block
*/
writel(rgmii_timing, RUBY_SYS_CTL_GMII_CLKDLL);
/* Release Ethernet busses from reset separately to emacs */
reset_mask = RUBY_SYS_CTL_RESET_NETSS | RUBY_SYS_CTL_RESET_IOSS;
writel(reset_mask, RUBY_SYS_CTL_CPU_VEC_MASK);
writel(reset_mask, RUBY_SYS_CTL_CPU_VEC);
if (emac1_cfg & EMAC_IN_USE) {
/*
* emac1 only or emac0 + emac1 configurations both require emac0
* to be taken out of reset, since both PHYs use a shared mdio bus
* starting from emac0
*/
reset_mask = RUBY_SYS_CTL_RESET_ENET0 | RUBY_SYS_CTL_RESET_ENET1;
} else if (emac0_cfg & EMAC_IN_USE) {
reset_mask = RUBY_SYS_CTL_RESET_ENET0;
}
#ifdef TOPAZ_AMBER_IP
amber_bus_flush_req(TOPAZ_AMBER_BUS_FLUSH_RGMII);
#endif
if (ext_reset) {
reset_mask |= RUBY_SYS_CTL_RESET_EXT;
}
if (reset_mask && (readl(RUBY_SYS_CTL_CPU_VEC) & reset_mask) != reset_mask) {
writel(reset_mask, RUBY_SYS_CTL_CPU_VEC_MASK);
if (ext_reset) {
writel(RUBY_SYS_CTL_RESET_EXT, RUBY_SYS_CTL_CPU_VEC);
mydelay(DELAY_40MILLISEC);
reset_mask &= ~RUBY_SYS_CTL_RESET_EXT;
}
writel(0, RUBY_SYS_CTL_CPU_VEC);
mydelay(DELAY_50MILLISEC);
}
/* Bring the EMAC out of reset */
writel(reset_mask, RUBY_SYS_CTL_CPU_VEC_MASK);
writel(reset_mask, RUBY_SYS_CTL_CPU_VEC);
writel(0, RUBY_SYS_CTL_MASK);
writel(0, RUBY_SYS_CTL_CPU_VEC_MASK);
#ifdef TOPAZ_AMBER_IP
amber_bus_flush_release(TOPAZ_AMBER_BUS_FLUSH_RGMII);
#endif
/*
* Trigger dummy MDIO read to set MDC clock
*/
writel(mii_value, RUBY_ENET0_BASE_ADDR + EMAC_MAC_MDIO_CTRL);
/*
* Remove EMAC DMA from soft reset; all other EMAC register
* writes result in bus hang if the EMAC is in soft reset
*/
if (emac0_cfg & EMAC_IN_USE) {
writel(0x0, RUBY_ENET0_BASE_ADDR + EMAC_DMA_CONFIG);
writel(0x0, RUBY_ENET0_BASE_ADDR + EMAC_DMA_CTRL);
}
if (emac1_cfg & EMAC_IN_USE) {
writel(0x0, RUBY_ENET1_BASE_ADDR + EMAC_DMA_CONFIG);
writel(0x0, RUBY_ENET1_BASE_ADDR + EMAC_DMA_CTRL);
}
}
#endif /* __ASSEMBLY__ */
#endif