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

📄 xscale.c

📁 smsc911x 网卡驱动 This the users/programmers guide for the LAN911x Linux Driver The following sections
💻 C
字号:
/***************************************************************************
 *
 * Copyright (C) 2004-2005  SMSC
 *
 * 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.
 *
 ***************************************************************************
 * File: xscale.c
 */

#ifndef USE_XSCALE
#error need to define USE_XSCALE
#endif

BOOLEAN Platform_IsValidDmaChannel(DWORD dwDmaCh)
{
	if(dwDmaCh<=16) {
		return TRUE;
	}
	return FALSE;
}

DWORD Platform_Initialize(
	PPLATFORM_DATA platformData,
	DWORD dwLanBase,DWORD dwBusWidth)
{
	DWORD mode=0;
	DWORD test=0;
	SMSC_TRACE("--> Platform_Initialize()");

	if(dwLanBase==0x0UL) {
		dwLanBase=LAN_CSBASE;
	}

	if(dwLanBase!=LAN_CSBASE) {
		SMSC_WARNING("PlatformInitialize: resetting dwLanBase from 0x%08lX to 0x%08X", dwLanBase, LAN_CSBASE);
		dwLanBase=LAN_CSBASE;
	}

#define BYTE_TEST_OFFSET	(0x64)
#define ID_REV_OFFSET		(0x50)
	switch(dwBusWidth) {
	case 16:
		mode=2;
		MSC2&=0x0000FFFFUL;
		MSC2|=0x8CD90000UL;
		test=(*(volatile unsigned long *)(dwLanBase+BYTE_TEST_OFFSET));
		if(test==0x87654321) {
			SMSC_TRACE(" 16 bit mode assigned and verified");
		} else {
			SMSC_WARNING(" failed to verify assigned 16 bit mode");
			dwLanBase=0;
		};break;
	case 32:
		mode=1;
		MSC2&=0x0000FFFFUL;
		MSC2|=0x8CD10000UL;
		test=(*(volatile unsigned long *)(dwLanBase+BYTE_TEST_OFFSET));
		if(test==0x87654321) {
			SMSC_TRACE(" 32 bit mode assigned and verified");
		} else {
			SMSC_WARNING(" failed to verify assigned 32 bit mode");
			dwLanBase=0;
		};break;
	default:
		mode=1;
		MSC2&=0x0000FFFFUL;
		MSC2|=0x8CD10000UL;
		{
			WORD dummy=0;
			test=(*(volatile unsigned long *)(dwLanBase+BYTE_TEST_OFFSET));
			dummy=(*(volatile unsigned short *)(dwLanBase+BYTE_TEST_OFFSET+2));
			if(test==0x87654321UL) {
				SMSC_TRACE(" 32 bit mode detected");
			} else {
				MSC2|=0x00080000UL;
				test=(*(volatile unsigned long *)(dwLanBase+BYTE_TEST_OFFSET));
				if(test==0x87654321UL) {
					SMSC_TRACE(" 16 bit mode detected");
					mode=2;
				} else {
					SMSC_WARNING(" neither 16 nor 32 bit mode detected.");
					dwLanBase=0;
				}
			}
			dummy=dummy;//make lint happy
		};break;
	}
	
	if(dwLanBase!=0) {
		DWORD idRev=(*(volatile unsigned long *)(dwLanBase+ID_REV_OFFSET));
		platformData->dwIdRev=idRev;
		switch(idRev&0xFFFF0000) {
		case 0x01180000UL:
		case 0x01170000UL:
			switch(mode) {
			case 1://32 bit mode
				MSC2 &= 0x0000FFFFUL;
				MSC2 |= 0x83710000UL;
				break;
			case 2://16 bit mode
				MSC2 &= 0x0000FFFFUL;
				MSC2 |= 0x83790000UL;
				break;			default:break;//make lint happy
			};break;
		default:break;//make lint happy
		}
	}

	SMSC_TRACE(" MSC2=0x%08X", MSC2);
	SMSC_TRACE("<-- Platform_Initialize()");

	return LAN_CSBASE;
}

BOOLEAN Platform_Is16BitMode(PPLATFORM_DATA platformData)
{
	SMSC_ASSERT(platformData!=NULL);

	if (MSC2 & 0x00080000)
		return TRUE;
	else
		return FALSE;
}void Platform_GetFlowControlParameters(	PPLATFORM_DATA platformData,	PFLOW_CONTROL_PARAMETERS flowControlParameters,	BOOLEAN useDma){	memset(flowControlParameters,0,sizeof(FLOW_CONTROL_PARAMETERS));	flowControlParameters->BurstPeriod=100;	flowControlParameters->IntDeas=0;	if(useDma) {		if(Platform_Is16BitMode(platformData)) {			switch(platformData->dwIdRev&0xFFFF0000) {			case 0x01180000UL:			case 0x01170000UL:				//117/118,16 bit,DMA				flowControlParameters->MaxThroughput=0x10C210UL;				flowControlParameters->MaxPacketCount=0x2DCUL;				flowControlParameters->PacketCost=0x82UL;				flowControlParameters->BurstPeriod=0x75UL;				flowControlParameters->IntDeas=0x1CUL;				break;			case 0x01160000UL:			case 0x01150000UL:				//115/116,16 bit,DMA				flowControlParameters->MaxThroughput=0x96CF0UL;				flowControlParameters->MaxPacketCount=0x198UL;				flowControlParameters->PacketCost=0x00UL;				flowControlParameters->BurstPeriod=0x73UL;				flowControlParameters->IntDeas=0x31UL;				break;			default:break;//make lint happy			}		} else {			switch(platformData->dwIdRev&0xFFFF0000) {			case 0x01180000UL:			case 0x01170000UL:				//117/118,32 bit,DMA				flowControlParameters->MaxThroughput=0x12D75AUL;				flowControlParameters->MaxPacketCount=0x332UL;				flowControlParameters->PacketCost=0xDBUL;				flowControlParameters->BurstPeriod=0x15UL;				flowControlParameters->IntDeas=0x0BUL;				break;			case 0x01160000UL:			case 0x01150000UL:				//115/116,32 bit,DMA				flowControlParameters->MaxThroughput=0xF3EB6UL;				flowControlParameters->MaxPacketCount=0x29BUL;				flowControlParameters->PacketCost=0x00UL;				flowControlParameters->BurstPeriod=0x41UL;				flowControlParameters->IntDeas=0x21UL;				break;			default:break;//make lint happy			}		}	} else {		if(Platform_Is16BitMode(platformData)) {			switch(platformData->dwIdRev&0xFFFF0000) {			case 0x01180000UL:			case 0x01170000UL:				//117/118,16 bit,PIO				flowControlParameters->MaxThroughput=0xAC3F4UL;				flowControlParameters->MaxPacketCount=0x1D2UL;				flowControlParameters->PacketCost=0x5FUL;				flowControlParameters->BurstPeriod=0x72UL;				flowControlParameters->IntDeas=0x02UL;				break;			case 0x01160000UL:			case 0x01150000UL:				//115/116,16 bit,PIO				flowControlParameters->MaxThroughput=0x7295CUL;				flowControlParameters->MaxPacketCount=0x136UL;				flowControlParameters->PacketCost=0x00UL;				flowControlParameters->BurstPeriod=0x6FUL;				flowControlParameters->IntDeas=0x38UL;				break;			default:break;//make lint happy			}		} else {			switch(platformData->dwIdRev&0xFFFF0000) {			case 0x01180000UL:			case 0x01170000UL:				//117/118,32 bit,PIO				flowControlParameters->MaxThroughput=0xCB4BCUL;				flowControlParameters->MaxPacketCount=0x226;				flowControlParameters->PacketCost=0x00UL;				flowControlParameters->BurstPeriod=0x77UL;				flowControlParameters->IntDeas=0x36UL;				break;			case 0x01160000UL:			case 0x01150000UL:				//115/116,32 bit,PIO				flowControlParameters->MaxThroughput=0x9E338UL;				flowControlParameters->MaxPacketCount=0x1ACUL;				flowControlParameters->PacketCost=0x00UL;				flowControlParameters->BurstPeriod=0x73UL;				flowControlParameters->IntDeas=0x31UL;				break;			default:break;//make lint happy			}		}	}}

void PlatformDisplayInfo(void);
void PlatformDisplayInfo(void)
{
}

BOOLEAN PlatformPossibleIRQ(int Irq);
BOOLEAN PlatformPossibleIRQ(int Irq)
{
	Irq=Irq;//make lint happy
	return TRUE;
}

BOOLEAN Platform_RequestIRQ(
	PPLATFORM_DATA platformData,
	DWORD dwIrq,
	irqreturn_t (*pIsr)(int a,void *b,struct pt_regs *c),
	void * dev_id)
{
	SMSC_ASSERT(platformData!=NULL);
	
	if(dwIrq==0xFFFFFFFFUL) {
		dwIrq=LAN_IRQ;
	}

	if(request_irq(dwIrq, pIsr, SA_INTERRUPT, "SMSC_LAN911x_ISR", dev_id)!=0)
	{
		SMSC_WARNING("Unable to use IRQ = %ld",dwIrq);
		return FALSE;
	}

	platformData->dwIrq = dwIrq;
	platformData->dev_id = dev_id;
	return TRUE;
}

DWORD Platform_CurrentIRQ(PPLATFORM_DATA platformData)
{
	SMSC_ASSERT(platformData!=NULL);
	return platformData->dwIrq;
}
void Platform_FreeIRQ(PPLATFORM_DATA platformData)
{
	if(platformData!=NULL) {
		free_irq(platformData->dwIrq,platformData->dev_id);
		platformData->dwIrq=0;
	} else {
		SMSC_ASSERT(FALSE);
	}
}

BOOLEAN Platform_DmaDisable(
	PPLATFORM_DATA platformData, const DWORD dwDmaCh)
{	
	// To avoid Lint error
	DWORD	temp;
	temp = dwDmaCh;
	temp = temp;

	platformData=platformData;//make lint happy

	DCSR(dwDmaCh) &= ~DCSR_RUN;
	while (!(DCSR(dwDmaCh) & DCSR_STOPSTATE)) {};

	return TRUE;
}

BOOLEAN Platform_DmaInitialize(PPLATFORM_DATA platformData, DWORD dwDmaCh)
{
	if(dwDmaCh<256)
		if(!Platform_DmaDisable(platformData, dwDmaCh)) {
			return FALSE;
		}

	return TRUE;
}

void PurgeCache(
	const void * const pStartAddress, 
	const DWORD dwLengthInBytes);
void PurgeCache(
	const void * const pStartAddress, 
	const DWORD dwLengthInBytes)
{
	DWORD dwCurrAddr, dwEndAddr, dwLinesToGo;
	
	dwCurrAddr = (DWORD)pStartAddress & CACHE_ALIGN_MASK;
	dwEndAddr = (((DWORD)pStartAddress) + dwLengthInBytes + (CACHE_LINE_BYTES - 1UL)) & CACHE_ALIGN_MASK;

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

	return;	
}

void Platform_CacheInvalidate(PPLATFORM_DATA platformData, const void * const pStartAddress, const DWORD dwLengthInBytes)
{
	platformData=platformData;//make lint happy
	PurgeCache(pStartAddress, dwLengthInBytes);
}

void Platform_CachePurge(PPLATFORM_DATA platformData, const void * const pStartAddress, const DWORD dwLengthInBytes)
{
	platformData=platformData;//make lint happy
	PurgeCache(pStartAddress, dwLengthInBytes);
}

/*
 * SRAM Mapping on Linux:
 *		Physical Address = 0xA000_0000 - 0xA3FF_FFFF (Size = 64MB)
 *		Virtual Address  = 0xC000_0000 - 0xC3FF_FFFF (Size = 64MB)
 *
 * Expansion Card (LAN911x) Mapping on Linux:
 *		Physical Address = 0x1400_0000 - 0x140F_FFFF (Size = 1MB)
 *      Virtual Address  = 0xF200_0000 - 0xF20F_FFFF (Size = 1MB)
 *		
 */
DWORD CpuToPhysicalAddr(const void * const pvCpuAddr);
DWORD CpuToPhysicalAddr(const void * const pvCpuAddr)
{
	const DWORD dwVirtAddr = (DWORD) pvCpuAddr;
	if ((dwVirtAddr >= 0xF2000000UL) && (dwVirtAddr <= 0xF20FFFFFUL))
	{
		//Expansion card memory
		return ((dwVirtAddr - MST_EXP_BASE) + MST_EXP_PHYS);
	}
	if ((dwVirtAddr >= 0xC0000000UL) && (dwVirtAddr <= 0xC3FFFFFFUL))
	{
		// Linux SDRAM
		return virt_to_bus(dwVirtAddr);
	}

	SMSC_WARNING("Wrong virtual address : 0x%08lx", dwVirtAddr);
	return (0xFFFFFFFFUL); //invalid/unrecognized address
}

BOOLEAN Platform_DmaStartXfer(PPLATFORM_DATA platformData, const DMA_XFER * const pDmaXfer)
{

	DWORD dwDmaCmd;
	DWORD dwLanPhysAddr, dwMemPhysAddr;
	DWORD dwAlignMask;

	platformData=platformData;//make lint happy

	//Validate the channel#
	/*
	if (pDmaXfer->dwDmaCh != 0UL) //always use channel 0 on XScale
	{
		printf("DMAStartXfer -- bad dwDmaCh=%ld\n", pDmaXfer->dwDmaCh);
		return FALSE;
	}
	*/

	//Check if the channel is currently running
	if (!(DCSR(pDmaXfer->dwDmaCh) & DCSR_STOPSTATE))
	{
		if (DCSR(pDmaXfer->dwDmaCh) & DCSR_RUN) 
		{
			SMSC_TRACE("DmaStartXfer -- requested channel (%ld) is still running", pDmaXfer->dwDmaCh);
			return FALSE;
		}
		else 
		{
			// DMA is not running yet.
			// Keep going..
			SMSC_WARNING("DmaStartXfer -- requested channel (%ld) is weird status", pDmaXfer->dwDmaCh);
		}
	}

	// calculate the physical transfer addresses
	dwLanPhysAddr = CpuToPhysicalAddr((void *)pDmaXfer->dwLanReg);
	dwMemPhysAddr = CpuToPhysicalAddr((void *)pDmaXfer->pdwBuf);

	dwLanPhysAddr += 0x800;

	// need CL alignment for CL bursts
	dwAlignMask = (CACHE_LINE_BYTES - 1UL);

	if ((dwLanPhysAddr & dwAlignMask) != 0UL)
	{
		SMSC_WARNING("DmaStartXfer -- bad dwLanPhysAddr (0x%08lX) alignment",
			dwLanPhysAddr);
		return FALSE;
	}

	//if ((dwMemPhysAddr & dwAlignMask) != 0UL)
	if ((dwMemPhysAddr & 0x03UL) != 0UL)
	{
		SMSC_WARNING("DmaStartXfer -- bad dwMemPhysAddr (0x%08lX) alignment",
			dwMemPhysAddr);
			return FALSE;
	}

	//validate the transfer size, On XScale Max size is 8k-1
	if (pDmaXfer->dwDwCnt >= 8192UL)
	{
		SMSC_WARNING("DmaStartXfer -- dwDwCnt =%ld is too big (1^20 bytes max on panax)", pDmaXfer->dwDwCnt);
		return FALSE;
	}

	//Note: The DCSR should be cleared, before writing the Target and Source addresses
	DCSR(pDmaXfer->dwDmaCh) = DCSR_NODESC; //get ready for the DMA

	//Set the Source and Target addresses
	dwDmaCmd = 0UL;
	if (pDmaXfer->fMemWr)
	{
		//RX
		DTADR(pDmaXfer->dwDmaCh) = dwMemPhysAddr;
		DSADR(pDmaXfer->dwDmaCh) = dwLanPhysAddr;
		dwDmaCmd |= DCMD_INCTRGADDR; //always increment the memory address
		dwDmaCmd |= DCMD_INCSRCADDR;
	}
	else
	{
		//TX
		DTADR(pDmaXfer->dwDmaCh) = dwLanPhysAddr;
		DSADR(pDmaXfer->dwDmaCh) = dwMemPhysAddr;
		dwDmaCmd |= DCMD_INCSRCADDR; //always increment the memory address
		dwDmaCmd |= DCMD_INCTRGADDR;
	}

	//Set the burst size, if cache line burst set to 32Bytes else set to the smallest
	dwDmaCmd |= DCMD_BURST32;

	dwDmaCmd |= (DCMD_LENGTH & (pDmaXfer->dwDwCnt << 2));
	DCMD(pDmaXfer->dwDmaCh) = dwDmaCmd ;
	DCSR(pDmaXfer->dwDmaCh) |= DCSR_RUN;
	
	return TRUE;
}

DWORD Platform_DmaGetDwCnt( PPLATFORM_DATA platformData, const DWORD dwDmaCh)
{
	platformData=platformData;//make lint happy
	return (((DCMD_LENGTH & DCMD(dwDmaCh)) >> 2));	
}

void Platform_DmaComplete(PPLATFORM_DATA platformData, const DWORD dwDmaCh)
{
	DWORD dwTimeOut=1000000;

	platformData=platformData;//make lint happy

	while((Platform_DmaGetDwCnt(platformData,dwDmaCh))&&(dwTimeOut))
	{
		udelay(1);
		dwTimeOut--;
	}
	if(!Platform_DmaDisable(platformData,dwDmaCh)) {
		SMSC_WARNING("Failed Platform_DmaDisable");
	}
	if(dwTimeOut==0) {
		SMSC_WARNING("Platform_DmaComplete: Timed out");
	}
}

DWORD Platform_RequestDmaChannel(PPLATFORM_DATA platformData)
{
	platformData=platformData;//make lint happy
	return TRANSFER_PIO;
}

void Platform_ReleaseDmaChannel(
	PPLATFORM_DATA platformData,
	DWORD dwDmaChannel)
{
	platformData=platformData;//make lint happy
	dwDmaChannel=dwDmaChannel;//make lint happy
	//since Platform_RequestDmaChannel
	//  never returns a dma channel
	//  then this function should never be called
	SMSC_ASSERT(FALSE);
}

⌨️ 快捷键说明

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