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

📄 dp83815.c

📁 三星2410的BSP开发包
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
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.

Module Name:  DP83815.c

Author: Kirk Gremillion (kirkgrem)

Abstract:  
    Plain Vanilla Routines for National Semiconductor DP83815.
    This mainly supports initialization and Sending/Receiving Ethernet 
    packets as well as interrupt handler.
    Minimum error handling is provided here...
    

    
Notes: 
    Code is meant to be used for ethernet download and debugging only and 
    is expected to run in Kernel Mode...

  This code assumes that you have a BIOS of some type that will set up the PCI device.  
  No hardware reset is performed, although configuration is.



    
--*/

#include <windows.h>
#include <halether.h>

#include <dp83815.h>

// DPUseIOSpace assumes an i486 CPU type.
#define DPUseIOSpace // use the IO space for accessing the device.  If it is not defined, we use Memory mapped IO.


BOOL bEbootImage = FALSE;

#define TO_VIRT(addr) (bEbootImage ? (ULONG)addr : ((ULONG)addr | 0x80000000))
#define TO_PHYS(addr) (bEbootImage ? (ULONG)addr : ((ULONG)addr & ~0x80000000))

////////////////////////////////////////////////////////////////////////////////
//  Misc utility functions 
//

#ifdef DPUseIOSpace

static void
DP_WRITE_PORT_ULONG(volatile PULONG addr, ULONG val)
{
    __asm {
        mov edx, addr
        mov eax, val
        out dx, eax
    }
}

static ULONG
DP_READ_PORT_ULONG(volatile PULONG addr)
{
    ULONG val;
    __asm {
        mov edx, addr
        in  eax, dx
        mov val, eax
    }
    return val;
}

#else  // DPUseIOSpace was not defined so we want to use memory addressing.  Redefine port IO for memory.


static void
DP_WRITE_PORT_ULONG(volatile PULONG addr, ULONG val)
{
    *addr = val;
}

static ULONG
DP_READ_PORT_ULONG(volatile PULONG addr)
{
    return *addr;
}

#endif  // end #ifdef DPUseIOSpace.




////////////////////////////////////////////////////////////////////////////////
//  DP83815ModifyLong()
//  Implements a Read-modify-write cycle for any DP_OPS register
//  caller supplies 'Value' as a DWORD with his needed bits (only) set or cleared.
//	Function will read register, mask this with 'ValueMask' and compare with
//  'Value'.  If equal, no write back is done.  If a change is needed, a copy of
//  the register value has the bits specified by 'ValueMask' cleared, and then
//  the caller's 'Value' is ORed in.  The result is then written out to Tag.
//
void
DPModifyLong(DWORD Tag, DWORD ValueMask, DWORD Value)
{
	DWORD dwRegister,dwTemp;
	dwTemp=(Value & ValueMask);  // We don't want to accidentally set any bits outside of ValueMask.
	if (dwTemp != Value)
	{
		PRINTF (1, ("DP83815: Misuse of DPModifyLong().  Possible error in register write.\r\n"));
		PRINTF (1, ("DP83815: Check alignment of Value and ValueMask. Spin Forever.\r\n"));
		while(1);
	}
	
	dwRegister=DPReadLong(Tag,DP_allbits);  // get the current register value
	dwTemp=(dwRegister & ValueMask); // see if the bits in question are already set as we want them.
	if (dwTemp==Value)
	{
		return;  // OK, we don't need to modify this register.  NO WRITE BACK IS DONE.
	}
	else
	{
		dwRegister=(dwRegister&(~ValueMask));  // clear the bits in our copy of the register
		dwRegister=(dwRegister|Value);  // OR in the caller's validated bits
		DPWriteLong(Tag,DP_allbits,dwRegister); // Write the new register value.
	}
	return;
}  // end DPModifyLong()


////////////////////////////////////////////////////////////////////////////////
//  DPDelay()
//  Implements an arbitrary wait loop.  Use only during Initialization please.
//

void
DPDelay(int i)
{
	
	for(;i>0;i--)
		DPReadLong(MyDP.UsedAddr, DP_allbits);
}



////////////////////////////////////////////////////////////////////////////////
//  DP83815InitDMABuffer()
//   
//  This function sets up the frame descriptors and associated buffers.
//	Each descriptor is allocated sizeof(DP83815FrameDescriptor) but always onto the next 4 byte boundary.
//	Each buffer is allocated BUFFSIZE bytes.
//	Allocation comes from the area defined by dwBuffAreaStartAddress.
//
BOOL
DP83815InitDMABuffer(DWORD dwBuffAreaStartAddress, DWORD dwBuffAreaSize)
{
	 // BUFFSIZE is defined in DP83815.h
	DWORD dwAllocationPointer, dwCloseTheLoopPointer;
	DWORD dwDescSize;
	int i,SetChar=0xBB;
	DWORD Scrap;

	// Buffer must be at least 4 bytes to even get through the alignment stage
	if(dwBuffAreaSize <0x04)
		return FALSE;  // Not enough buffer to even figure out the alignment.

        // We can be called by eboot code or by OAL code - decide who's calling 
        // so we can initialize buffer chain with correct addresses.
        if (dwBuffAreaStartAddress & 0x80000000)
            bEbootImage = FALSE;
        else
            bEbootImage = TRUE;
        
        dwBuffAreaStartAddress = TO_PHYS(dwBuffAreaStartAddress);

	// First, make sure that start address is 32-bit aligned, and if not adjust both it and dwBuffAreaSize
	Scrap= dwBuffAreaStartAddress%4;
	Scrap= (Scrap ? (4-Scrap):Scrap);
	dwBuffAreaStartAddress= dwBuffAreaStartAddress + Scrap;
	dwBuffAreaSize = dwBuffAreaSize - Scrap;
	
	// Clear the entire region. 
	memset((void *) TO_VIRT(dwBuffAreaStartAddress), SetChar, dwBuffAreaSize);

	// Now lets calculate the size and alignment for a descriptor.
	dwDescSize = sizeof(DP83815FrameDescriptor);
	Scrap=dwDescSize%4;
	Scrap= (Scrap ? (4-Scrap):Scrap);
	dwDescSize= dwDescSize + Scrap; // make sure we allocate at least to the next 32bit boundary. (Requirement of DP83815 device)

	// Need at least enough DMA buffer space for 4 (3 Tx and 1 Rx) descriptor/buffer pairs.
	if(dwBuffAreaSize < (4*(dwDescSize+BUFFSIZE)))
		return FALSE; // not enough buffer to work with.

	// Set up 3 Tx descriptors and buffers in a ring.
	dwAllocationPointer=dwBuffAreaStartAddress;
	dwCloseTheLoopPointer=dwAllocationPointer;
	for (i=0;i<3;i++)
	{
	MyDP.pCurrentTxDescriptor= (pDP83815FrameDescriptor)TO_VIRT(dwAllocationPointer); // beginning of descriptor.
	dwAllocationPointer += dwDescSize;
	MyDP.pCurrentTxDescriptor->bufptr=dwAllocationPointer;  //beginning of buffer
	dwAllocationPointer += BUFFSIZE;  // now Allocation pointer is set for allocation of next descriptor.
	MyDP.pCurrentTxDescriptor->link= (pDP83815FrameDescriptor) dwAllocationPointer;  
	MyDP.pCurrentTxDescriptor->cmdsts= ((DP83815_cmdsts_SIZE&BUFFSIZE)|(DP83815_cmdsts_OWN&0x0));  // size of buffer allocated, and clear OWN bit
	}	// end for( 3 times)
	MyDP.pCurrentTxDescriptor->link=(pDP83815FrameDescriptor) dwCloseTheLoopPointer; // close the Tx ring.
	MyDP.pCurrentTxDescriptor= (pDP83815FrameDescriptor)TO_VIRT(MyDP.pCurrentTxDescriptor->link); 

	// Just for grins, let's traverse the Tx ring.  If we get lost, we don't want to go any farther anyway.
	do
	{
		MyDP.pCurrentTxDescriptor=(pDP83815FrameDescriptor)TO_VIRT(MyDP.pCurrentTxDescriptor->link);
	} while (MyDP.pCurrentTxDescriptor != (pDP83815FrameDescriptor)TO_VIRT(dwCloseTheLoopPointer));

	DPReadLong(DP_OPS_ISR,DP_allbits) ;  // not quite sure why, but have to clear ISR before proceeding.

	// set up Rx descriptors, linked in a ring until we run out of Buffer space.
	dwCloseTheLoopPointer=dwAllocationPointer;
	while (dwAllocationPointer < (dwBuffAreaStartAddress+dwBuffAreaSize-(dwDescSize+BUFFSIZE))) //while(we still have room in the buffer space for another descriptor/buffer pair)
	{
		MyDP.pCurrentRxDescriptor=(pDP83815FrameDescriptor)TO_VIRT(dwAllocationPointer); // beginning of descriptor.  
		dwAllocationPointer += dwDescSize; // allocate enough memory for the descriptor.
		MyDP.pCurrentRxDescriptor->bufptr=dwAllocationPointer;  //beginning of buffer
		dwAllocationPointer += BUFFSIZE;  // Allocate buffer.  Now Allocation pointer is set for allocation of next descriptor.
		MyDP.pCurrentRxDescriptor->link= (pDP83815FrameDescriptor)dwAllocationPointer; // That will be the beginning of the next descriptor.
		MyDP.pCurrentRxDescriptor->cmdsts= ((DP83815_cmdsts_SIZE&BUFFSIZE)|DP83815_cmdsts_MORE);  // size of buffer allocated, and clear OWN bit, set MORE bit.
	}  // end while(we still have room in the buffer space)
	MyDP.pCurrentRxDescriptor->link= (pDP83815FrameDescriptor) dwCloseTheLoopPointer;  // which is still pointing to the first Rx descriptor.
	MyDP.pCurrentRxDescriptor=(pDP83815FrameDescriptor)TO_VIRT(MyDP.pCurrentRxDescriptor->link);  // now MyDP.pCurrentRxDescriptor is pointing at the first Rx descriptor we created.

	// Just for grins, let's traverse the Rx ring.  Again, better to wander into space now than later.
	i=0;
	do
	{
		MyDP.pCurrentRxDescriptor=(pDP83815FrameDescriptor)TO_VIRT(MyDP.pCurrentRxDescriptor->link);
	}	while (MyDP.pCurrentRxDescriptor != (pDP83815FrameDescriptor)TO_VIRT(dwCloseTheLoopPointer));
	
	return TRUE;

}   //  DP83815InitDMABuffer()


////////////////////////////////////////////////////////////////////////////////
//  DP83815Disable()
// Turns off the Tx and Rx state machines.  This needs to be done after download
// since the state machines are free running and would keep running even through
// kernel start.
//
void
DP83815Disable(void)
{
	

	DPModifyLong(DP_OPS_CR,DP_OPS_cr_TXD,DP_OPS_cr_TXD); // turn off the transmitter.
	while((DPReadLong(DP_OPS_CR,DP_OPS_cr_TXE)))  // this tells us when TXE goes reset.
	{
		PRINTF (1, ("DP83815: Waiting for transmitter to stop.\r\n"));
		DPDelay(100);
	}
	PRINTF (1, ("DP83815:Transmitter stopped.\r\n"));

	DPModifyLong(DP_OPS_CR,DP_OPS_cr_RXD,DP_OPS_cr_RXD); // turn off the receiver.
	while((DPReadLong(DP_OPS_CR,DP_OPS_cr_RXE)))  // this tells us when RXE goes reset.
	{
		PRINTF (1, ("DP83815: Waiting for Receiver to stop.\r\n"));
		DPDelay(100);
	}
	PRINTF (1, ("DP83815: Receiver stopped.\r\n"));

}  //  DP83815Disable()




////////////////////////////////////////////////////////////////////////////////
//  DP83815Init()
//
int
DP83815Init(BYTE *pbBaseAddress, ULONG dwMemOffset, USHORT MacAddr[3])
{
 	ULONG	ulScrap=0,ulScrapOld=0;
	BOOL	test;
	DWORD	dwScrap=0;



#ifdef DPUseIOSpace
	PRINTF (1, ("DP83815: IO Space was chosen. \r\n"));
#else
	PRINTF (1, ("DP83815: Mem Space was chosen. \r\n"));
#endif
	
	// get the base address into our local structure.
	MyDP.UsedAddr= (DWORD) pbBaseAddress; 
	
	//Set our global MemOffset based on input parameter
        MemOffset = dwMemOffset;

	DP83815Disable();

	//
	// Soft Reset - 
	//
	DPWriteLong(DP_OPS_CR,DP_allbits,DP_OPS_cr_RST);
	while(DPReadLong(DP_OPS_CR, DP_OPS_cr_RST));


	//Report the chip revision number.
	PRINTF (1, ("DP83815: Silicon Revision number: 0x%x \r\n",  DPReadLong(DP83815_SRR, DP_allbits)));

	
	// Load up EEPROM defaults
	DPModifyLong(DP_OPS_PTSCR,DP_OPS_ptscr_EELOAD_EN,DP_OPS_ptscr_EELOAD_EN);// Tell device to load defaults from EEPROM.
	while(DPReadLong(DP_OPS_PTSCR,DP_OPS_ptscr_EELOAD_EN)); //Spin until finished reading EEPROM.
	
	// Fill wMAC array from PMATCH registers.
	test=DP83815ReadMacAddr(MacAddr);  // We can do this after we have finished reading the EEPROM.
	if (!test)
		return FALSE;


	// Config the transmit register. 
	DPWriteLong( DP_OPS_TXCFG, DP_allbits,0x10C00230 ); 
	// This one write breaks out like this: (MSB down to LSB)
	/*
			CSI:		0  Carrier Sense Ignore
			HBI:		0  HeartBeat Ignore

⌨️ 快捷键说明

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