⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xscale-50.c

📁 SMSC9118网卡驱动
💻 C
字号:
/*****************************************************************************
   
	Copyright (c) 2004-2006 SMSC. All rights reserved.

	Use of this source code is subject to the terms of the SMSC Software
	License Agreement (SLA) under which you licensed this software product.	 
	If you did not accept the terms of the SLA, you are not authorized to use
	this source code. 

	This code and information is provided as is without warranty of any kind,
	either expressed or implied, including but not limited to the implied
	warranties of merchantability and/or fitness for a particular purpose.
	 
	File name   : xscale.c
	Description : xscale related Routines

	History	    :
		03-16-05 WH			First Release
		08-12-05 MDG		ver 1.01 
			- add LED1 inversion, add PHY work around
		11-07-05 WH			ver 1.02
			- Fixed middle buffer handling bug
			  (Driver didn't handle middle buffers correctly if it is less than 
               4bytes size)
			- workaround for Multicast bug
			- Workaround for MAC RXEN bug
		11-17-05 WH			ver 1.03
			- 1.02 didn't have 1.01 patches
			- 1.03 is 1.02 + 1.01
		12-06-05 WH			ver 1.04
			- Fixed RX doesn't work on Silicon A1 (REV_ID = 0x011x0002)
			- Support SMSC9118x/117x/116x/115x family
		02-27-05 WH			ver 1.05
			- Fixing External Phy bug that doesn't work with 117x/115x
		03-23-05 WH			ver 1.06
			- Put the variable to avoid PHY_WORKAROUND for External PHY
			- Change product name to 9118x->9218, 9115x->9215
		07-26-06 WH, MDG, NL		ver 1.07
			- Add RXE and TXE interrupt handlers
			- Workaround Code for direct GPIO connection from 9118 family 
			  Interrupt (Level Interrupt -> Edge Interrupt)
			- Change GPT interrupt interval to 200mSec from 50mSec
			- clean up un-used SH3 code
 		08-25-06  WH, MDG, NL       ver 1.08
		    - Fixed RXE and TXE interrupt handlers bug
			- support for direct and nondirect Interrupt

*****************************************************************************/
/*lint -save*/
/*lint -e14 -e43 -e46 -e123 -e427 -e537 -e620 -e652 -e659 -e683*/
/*lint -e726 -e760 -e761 -e762 -e763 -e767 -e773 -e793 -e806 -e828 -e912*/
/*lint -e935 -e937 -e950 -e955 -e956 -e957 -e958 -e959 -e960 -e961 -e962*/
/*lint -e973 -e1916*/
#include <windows.h>
#include <Pkfuncs.h>
/*lint -restore*/
#include "smsc9118.h"

static volatile PDWORD		pdwGpioCtrl;

extern DWORD	ReadCLKCFG(void);

void PlatformSetBusWidth(const DWORD dwBusWidth)
{
	PHYSICAL_ADDRESS	PhysAddr;
	volatile PDWORD		pdwMemCtrl;

	PhysAddr.LowPart = (DWORD)BULVERDE_BASE_REG_PA_MEMC;
	PhysAddr.HighPart = -1L;
	pdwMemCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
	if (pdwMemCtrl == NULL)
	{
		SMSC_WARNING0("Failed to get Virtual address of MemController\r\n");
	}
	else
	{
		// pdwMemCtrl[4]  : MSC2
		if (dwBusWidth == 16UL)
		{
			pdwMemCtrl[4] = pdwMemCtrl[4] | 0x00080000UL;
		}
		else if (dwBusWidth == 32UL)
		{
			pdwMemCtrl[4] = pdwMemCtrl[4] & 0xFFF7FFFFUL;
		}
		else
		{
			SMSC_WARNING0("Wrong Bus Width. Should be 16 ro 32. Set to 32bit as default.\r\n");
			pdwMemCtrl[4] = pdwMemCtrl[4] & 0xFFF7FFFFUL;
		}
	}

	MmUnmapIoSpace(pdwMemCtrl, (ULONG)PAGE_SIZE);
}

/* PlatformInitialize: 
 *   perform any platform initialization necessary to make the Lan9118 visible.
 *   This function must be called before PlatformGetLanBase
 */
void PlatformInitialize()
{
	PHYSICAL_ADDRESS	PhysAddr;
	volatile PDWORD		pdwMemCtrl;

	SMSC_TRACE0(DBG_INIT, "+PlatformInitialize()\r\n");

	PhysAddr.LowPart = (DWORD)BULVERDE_BASE_REG_PA_MEMC;
	PhysAddr.HighPart = -1L;
	pdwMemCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
	if (pdwMemCtrl == NULL)
	{
		SMSC_WARNING0("Failed to get Virtual address of MemController\r\n");
	}
	else
	{
		SMSC_TRACE0(DBG_INIT, "Set Default Bus Timing for SMSC912x\r\n");
		// pdwMemCtrl[4]  : MSC2
		pdwMemCtrl[4] = pdwMemCtrl[4] & 0x0000FFFFUL;
		pdwMemCtrl[4] = pdwMemCtrl[4] | 0x8CD10000UL;	// 32bit as default
	}
	MmUnmapIoSpace(pdwMemCtrl, (ULONG)PAGE_SIZE);

#ifdef	SMSC_DIRECT_INTR
	RETAILMSG(1, (TEXT("Set GPIO118 to GPIO mode, Input and Falling Edge\r\n")));
	// Set GPIO 118 to GPIO mode, Input and Falling Edge
	PhysAddr.LowPart = (DWORD)BULVERDE_BASE_REG_PA_GPIO;
	PhysAddr.HighPart = -1L;
	pdwGpioCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
	if (pdwGpioCtrl == NULL)
	{
		SMSC_WARNING0("Failed to get Virtual address of Gpio\r\n");
	}
	else
	{
		// GPDR1 (0x010)
		pdwGpioCtrl[0x10/4] &= (~(1<<12));			// PD118 as Input
		// GAFR1_L (0x05C)
		pdwGpioCtrl[0x5C/4] &= (~(3<<24));			// PD118 as GPIO
		// GEDR1 (0x04C)
		pdwGpioCtrl[0x4C/4] = (1<<12);				// Clear any pending one
		// GFER1 (0x130)
		pdwGpioCtrl[0x40/4] |= (1<<12);				// PD118 as Falling Edge
		// GRER1 (0x13c)
		pdwGpioCtrl[0x34/4] &= (~(1<<12));			// PD118 as No Rising Edge
	}

	// do not unmap pdwGpioCtrl
	// pdwGpioCtrl is used in PlatformEnableGpioInterrupt(void)
//	MmUnmapIoSpace(pdwGpioCtrl, (ULONG)PAGE_SIZE);
#endif

	SMSC_TRACE0(DBG_INIT, "+PlatformInitialize()\r\n");
}

void PlatformSetBusTiming(const DWORD dwChipIdReg)
{
	PHYSICAL_ADDRESS	PhysAddr;
	volatile PDWORD		pdwMemCtrl;
	DWORD				dwChipId;

	SMSC_TRACE0(DBG_INIT, "+PlatformSetBusTiming()\r\n");
	dwChipId = dwChipIdReg & 0xFFFF0000UL;
	if ((dwChipId == 0x01180000UL) ||
		(dwChipId == 0x01170000UL) ||
		(dwChipId == 0x01120000UL) ||
		(dwChipId == 0x118A0000UL) ||
		(dwChipId == 0x117A0000UL))
	{
		PhysAddr.LowPart = (DWORD)BULVERDE_BASE_REG_PA_MEMC;
		PhysAddr.HighPart = -1L;
		pdwMemCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
		if (pdwMemCtrl == NULL)
		{
			SMSC_WARNING0("Failed to get Virtual address of MemController\r\n");
		}
		else
		{
			// pdwMemCtrl[4]  : MSC2
			pdwMemCtrl[4] = pdwMemCtrl[4] & 0x0008FFFFUL;	// keep 16/32bit flag
			pdwMemCtrl[4] = pdwMemCtrl[4] | 0x83710000UL;
		}

		MmUnmapIoSpace(pdwMemCtrl, (ULONG)PAGE_SIZE);
	}
	SMSC_TRACE0(DBG_INIT, "-PlatformSetBusTiming()\r\n");
}

/* PlatformDisplayInfo:
 *   Will display info specific to the platform, such as
 *   processor registers, or DMA configurations
 */
void PlatformDisplayInfo()
{
	PDWORD		pPtr;
	BOOL		bRet;
	DWORD		msc2, mdrefr;
	DWORD		cccr, ccsr, clkcfg;
	DWORD		L, M, N2, r_clk, t_clk, s_clk, m_clk, k0db, k1db;

	SMSC_TRACE0(DBG_INIT, "+PlatformDisplayInfo()\r\n");
	pPtr = (PDWORD)VirtualAlloc((LPVOID)0, (DWORD)PAGE_SIZE, (DWORD)MEM_RESERVE, (DWORD)PAGE_NOACCESS);	
	bRet = VirtualCopy((PVOID)pPtr, (PVOID)(0x48000000UL>>8), 1024UL, (DWORD)(PAGE_READONLY | PAGE_PHYSICAL | PAGE_NOCACHE));
	if (bRet == TRUE) {
		msc2 = pPtr[4];
		mdrefr = pPtr[1];
		SMSC_TRACE1(DBG_INIT, "MDREFR = 0x%08x\r\n", mdrefr);
		SMSC_TRACE1(DBG_INIT, "MSC2 = 0x%08x\r\n", msc2);

	}
	else {
		SMSC_WARNING1("Error! at VirtualCopy(). ErrNo = %d\r\n", GetLastError());
		bRet = VirtualFree((PVOID)pPtr, 0UL, (DWORD)MEM_RELEASE);
		return;
	}
	bRet = VirtualFree((PVOID)pPtr, 0UL, (DWORD)MEM_RELEASE);

	pPtr = (PDWORD)VirtualAlloc((LPVOID)0UL, (DWORD)PAGE_SIZE, (DWORD)MEM_RESERVE, (DWORD)PAGE_NOACCESS);	

	bRet = VirtualCopy((PVOID)pPtr, (PVOID)((DWORD)0x41300000UL>>8), 1024UL, (DWORD)(PAGE_READONLY | PAGE_PHYSICAL | PAGE_NOCACHE));
	if (bRet == TRUE) {
		cccr = pPtr[0];
		ccsr = pPtr[3];
		clkcfg = ReadCLKCFG();
		SMSC_TRACE1(DBG_INIT, "CCCR = 0x%08x\r\n", cccr);
		SMSC_TRACE1(DBG_INIT, "CCSR = 0x%08x\r\n", ccsr);
		SMSC_TRACE1(DBG_INIT, "CLKCFG = 0x%08x\r\n", clkcfg);

		L = ccsr & 0x1FUL;
		N2 = (ccsr >> 7) & 0x07UL;

		if (L <= 10UL) 
		{
			M = 1UL;
		}
		else if (L <= 20UL) 
		{
			M = 2UL;
		}
		else 
		{
			M = 4UL;
		}

		r_clk = (L * 13000000UL);
		t_clk = (L * 13000000UL * N2) / 2UL;

		if (clkcfg & 0x08UL)
		{
			s_clk = r_clk;		// Fast Clk Mode
		}
		else
		{
			s_clk = r_clk / 2UL;
		}

		if (cccr & 0x2000000UL)
		{
			m_clk = s_clk;		// Alt setting
		}
		else
		{
			m_clk = r_clk / M;
		}
		if (mdrefr & (1UL<<29))
		{
			k0db = 4UL;
		}
		else if (mdrefr & (1UL<<14))
		{
			k0db = 2UL;
		}
		else
		{
			k0db = 1UL;
		}

		if (mdrefr & (1UL<<17))
		{
			k1db = 2UL;
		}
		else
		{
			k1db = 1UL;
		}

		if (clkcfg & 0x1UL) 
		{
			SMSC_TRACE4(DBG_INIT, "Turbo Mode Clk: %d.%02dMHz (*%d.%d)\r\n",
				(ULONG)(t_clk/1000000UL), (ULONG)((t_clk%1000000UL)/10000UL), 
				(ULONG)(N2/2UL), (ULONG)((N2%2UL)*5UL));
		}
		else 
		{
			SMSC_TRACE3(DBG_INIT, "Run Mode Clk: %d.%02dMHz (*%d)\r\n", 
				(ULONG)(r_clk/1000000UL), (ULONG)((r_clk%1000000UL)/1000000UL), 
				L);
		}
		SMSC_TRACE5(DBG_INIT, "MemClk: %d.%02dMHz (Alt=%d, SDCLK[0]=/%d, SDCLK[1]=/%d\r\n", 
				(ULONG)(m_clk/1000000UL), 
				(ULONG)((m_clk % 1000000UL)/10000UL), 
				(ULONG)((cccr>>25UL)&1UL), k0db, k1db);
		SMSC_TRACE2(DBG_INIT, "SysClk: %d.%02dMHz\r\n", 
				(ULONG)(s_clk/1000000UL), 
				(ULONG)((s_clk%1000000UL)/10000UL));

		if (mdrefr & (1UL<<20UL))
		{
			SMSC_TRACE0(DBG_INIT, "APD is ON\r\n");
		}
		else
		{
			SMSC_TRACE0(DBG_INIT, "APD is OFF\r\n");
		}
	}
	else 
	{
		SMSC_WARNING1("Error! at VirtualCopy(). ErrNo = %d\r\n", GetLastError());
	}
	bRet = VirtualFree((PVOID)pPtr, 0UL, (DWORD)MEM_RELEASE);
	SMSC_TRACE0(DBG_INIT, "-PlatformDisplayInfo()\r\n");
}

BOOL DmaStartXfer(const DMA_XFER * const dmaXfer)
{
    const PBULVERDE_DMA_REG pDmaBase = (PBULVERDE_DMA_REG)(dmaXfer->DMABaseVA);
	const DWORD dwDmaCh = dmaXfer->dwDmaCh;
	DWORD dwDmaCmd;
	DWORD dwAlignMask;
	volatile DWORD dwLanPhysAddr, dwMemPhysAddr;

    // 1. validate the requested channel #
	if (dwDmaCh > 10UL)
	{
		SMSC_WARNING1("DmaStartXfer -- bad dwDmaCh=%ld\n", dwDmaCh);
		return FALSE;
	}

	// 2. make sure the channel's not already running
	if (!(pDmaBase->dcsr[dwDmaCh] & DCSR_STOPSTATE))
	{
		if (pDmaBase->dcsr[dwDmaCh] & DCSR_RUN)
		{
			SMSC_WARNING1("DmaStartXfer -- requested channel (%ld) is still running\n", dmaXfer->dwDmaCh);
			return FALSE;
		}
	}

	// 3. calculate the physical transfer addresses
    dwMemPhysAddr = (DWORD)(dmaXfer->pdwBuf);
	dwLanPhysAddr = (DWORD)(dmaXfer->dwLanReg + 0x800UL);

	// 4. validate the address alignments
	if (dmaXfer->fClBurst)
	{
		// need CL alignment for CL bursts
		dwAlignMask = (CACHE_LINE_BYTES - 1UL);
	}
	else
	{
		// no burst, so DW alignment is OK
		dwAlignMask = 3UL;
	}

	if ((dwLanPhysAddr & dwAlignMask) != 0UL)
	{
		SMSC_WARNING2("DmaStartXfer -- bad dwLanPhysAddr (0x%08lX) alignment, fClBurst=%s\r\n", dwLanPhysAddr, dmaXfer->fClBurst?TEXT("TRUE"):TEXT("FALSE"));
		return FALSE;
	}

	if ((dwMemPhysAddr & 0x03UL) != 0UL)
	{
		SMSC_WARNING2("DmaStartXfer -- bad dwMemPhysAddr (0x%08lX) alignment, fClBurst=%s\r\n", dwMemPhysAddr, dmaXfer->fClBurst?TEXT("TRUE"):TEXT("FALSE"));
		return FALSE;
	}

	// 5. validate the transfer size & alignment
	if (dmaXfer->dwDwCnt >= 8192UL)
	{
		SMSC_WARNING1("DmaStartXfer -- dwDwCnt =%ld is too big\r\n", dmaXfer->dwDwCnt);
		return FALSE;
	}

	pDmaBase->dcsr[dwDmaCh] = DCSR_NODESC;

	dwDmaCmd = 0x00UL;
	// Select correct Ch and set SRC, DST and counter
	if (dmaXfer->fMemWr == TRUE)
	{
        // Read from 118
		// Set Source and destination addresses
		pDmaBase->ddg[dwDmaCh].dtadr = (UINT)dwMemPhysAddr;
		pDmaBase->ddg[dwDmaCh].dsadr = (UINT)dwLanPhysAddr;

		dwDmaCmd |= (DWORD)DCMD_INCTRGADDR;
		dwDmaCmd |= (DWORD)DCMD_INCSRCADDR;
	}
	else
	{
        // Write to 118
		// Set Source and destination addresses
		pDmaBase->ddg[dwDmaCh].dtadr = (UINT)dwLanPhysAddr;
		pDmaBase->ddg[dwDmaCh].dsadr = (UINT)dwMemPhysAddr;

		dwDmaCmd |= DCMD_INCSRCADDR;
		dwDmaCmd |= DCMD_INCTRGADDR;
	}

	// Set the transmit size in terms of the xfer mode
	if (dmaXfer->fClBurst == TRUE)
	{
		dwDmaCmd |= DCMD_BURST32;
	}
	else
	{
		dwDmaCmd |= DCMD_BURST8;
	}

	dwDmaCmd |= (DCMD_LENGTH & (dmaXfer->dwDwCnt << 2UL));

	pDmaBase->ddg[dwDmaCh].dcmd = (UINT)dwDmaCmd;
	pDmaBase->dcsr[dwDmaCh] |= DCSR_RUN;
	// DMA Transfering....
	if (pDmaBase->dcsr[dwDmaCh] & DCSR_BUSERR) {
		SMSC_WARNING0("DMA BusError!\r\n");
	}

	return TRUE;
}

BOOL DmaInitialize(NDIS_HANDLE hMiniportAdapterContext)
{
    CPCSMSC9118_ADAPTER pAdapter = (PSMSC9118_ADAPTER)(hMiniportAdapterContext);

	// Make Lint Happy
    hMiniportAdapterContext = hMiniportAdapterContext;

    SMSC_TRACE0(DBG_DMA,"+DmaInitialize()\n");
    SMSC_ASSERT(pAdapter);
    SMSC_TRACE0(DBG_DMA,"-DmaInitialize()\n");
	return TRUE;
}

DWORD DmaGetDwCnt(const DMA_XFER * const dmaXfer, const DWORD dwDmaCh)
{
    const volatile BULVERDE_DMA_REG * const pDmaBase = (PBULVERDE_DMA_REG)(dmaXfer->DMABaseVA);

	return ((DCMD_LENGTH & (DWORD)pDmaBase->ddg[dwDmaCh].dcmd) >> 2UL);
}

void DmaDisable(const DMA_XFER * const dmaXfer, const DWORD dwDmaCh)
{
    BULVERDE_DMA_REG * const pDmaBase = (PBULVERDE_DMA_REG)(dmaXfer->DMABaseVA);

	pDmaBase->dcsr[dwDmaCh] &= ~DCSR_RUN;
	while (!(pDmaBase->dcsr[dwDmaCh] & DCSR_STOPSTATE))
	{
	}
}

void DmaComplete(const DMA_XFER * const dmaXfer, const DWORD dwDmaCh) 
{
	DWORD 	dwTimeOut = 1000000UL;

	while ((DmaGetDwCnt(dmaXfer, dwDmaCh)) && (dwTimeOut))
	{
		SMSC_MICRO_DELAY(1U);
		dwTimeOut--;
	}

	if (dwTimeOut == 0UL) {
		SMSC_WARNING0("DmaComplete: Timed out\n");
	}
	
	DmaDisable(dmaXfer, dwDmaCh);
}

void CleanCacheLine(DWORD dwAddr);
void DrainWriteBuffers(void);
ULONG GetPID(void);

VOID BufferCacheFlush(const void * const pucBufAddress, const DWORD uiBufLen)
{
	DWORD	dwCurrAddr, dwEndAddr, dwLinesToGo;

	dwCurrAddr = (DWORD)pucBufAddress & ~(CACHE_LINE_BYTES-1UL);
	dwEndAddr = (((DWORD)pucBufAddress) + uiBufLen + CACHE_LINE_BYTES) & ~(CACHE_LINE_BYTES-1UL);

	dwLinesToGo = (dwEndAddr - dwCurrAddr) / CACHE_LINE_BYTES;
	while (dwLinesToGo)
	{
		CleanCacheLine(dwCurrAddr+GetPID());
		dwCurrAddr += CACHE_LINE_BYTES;
		dwLinesToGo--;
	}
	DrainWriteBuffers();
}

void PlatformEnableGpioInterrupt(void)
{
#ifdef	SMSC_DIRECT_INTR
	if (pdwGpioCtrl != NULL)
	{
		// GFER1 (0x40)
		pdwGpioCtrl[0x40/4] |= (1<<12);				// GPIO44 as Falling Edge
	}
#endif
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -