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

📄 ata.c

📁 常见卡(SD,NAND,XD,MS,ATA,CF)完整DRIVER
💻 C
字号:
/*
*******************************************************************************
*                               Magic Pixel
*                  5F, No.3, Creation Road III, Science_Based 
*                   Industrial Park, Hsinchu, Taiwan, R.O.C
*               (c) Copyright 2004, Magic Pixel Inc, Hsinchu, Taiwan
*
* All rights reserved. Magic Pixel's source code is an unpublished work and the 
* use of a copyright notice does not imply otherwise. This source code contains
* confidential, trad secret material. Any attempt or participation in 
* deciphering, decoding, reverse engineering or in ay way altering the source 
* code is strictly prohibited, unless the prior written consent of Magic 
* Pixel is obtained.
*
* Filename      : ata.c
* Programmer(s) : 
* Created       : 
* Descriptions  :
*******************************************************************************
*/
/*
// define this module show debug message or not,  0 : disable, 1 : enable
*/

#define LOCAL_DEBUG_ENABLE 0

/*
// Include section 
*/

#include "global612.h"
#include "mpTrace.h"
#include "uti.h"
#include "ata.h"
#include "devio.h"
#include "taskid.h"
#include "ui.h"
#include "utilregfile.h"
//#include "fs.h"

/*
// Constant declarations
*/
#if HD_ENABLE
#define ATA_TIMEOUT             0x400000

// define the HD command code
#define ATA_READ_SECTOR			0x2000
#define ATA_READ_SECTOR_EX		0x2400
#define ATA_WRITE_SECTOR		0x3000
#define ATA_WRITE_SECTOR_EXT		0x3400
#define ATA_READ_VERIFY			0x4000
#define ATA_READ_MULTIPLE		0xc400
#define ATA_WRITE_MULTIPLE		0xc500
#define ATA_SET_MULTIPLE		0xc600
#define ATA_IDENTIFY_DRIVE		0xec00
#define ATA_FEATURE_SET         0xef00
#define ATA_READ_DMA            0xc800
#define ATA_WRITE_DMA           0xca00
#define ATA_WRITE_DMA_EXT           0x3500
#define ATA_SETMAX_ADDRESS_EX	0x3700
#define ATA_READ_DMA_EX	0x2500

// define ATA tramsfer mode
#define ATA_PIO_MODE            0x00
#define ATA_MULTI_DMA_MODE      0x20
#define ATA_ULTRA_DMA_MODE      0x40

// ATA register definition
// field define for ATA DMA control register
#define ATA_DMA_IN              0x00000000
#define ATA_DMA_OUT             0x00020000

#define ATA_MULTI_DMA           0x00010000
#define ATA_ULTRA_DMA           0x00050000
#define ATA_NONE_DMA            0x00000000


#define ATA_PIO_TIMING          	0x00298321
#define ATA_MDMA0_TIMING 		0x00000d23
#define ATA_MDMA1_TIMING 		0x00000952
#define ATA_MDMA2_TIMING 		0x00000101
#define ATA_UDMA0_TIMING 		0x0000422b
#define ATA_UDMA1_TIMING 		0x000021ab
#define ATA_UDMA2_TIMING 		0x0000192b
#define ATA_UDMA3_TIMING 		0x000010ab
#define ATA_UDMA4_TIMING 		0x000008ab


#define ATA_DELAY  0

#define HD_ICAUSE           BIT2

///
///@defgroup ATA HardDisk
///@ingroup CONSTANT
///@{

///@}
/*
// Structure declarations
*/
struct ST_ATAINFO_TAG
{
	DWORD dwAtaDmaMode;
	WORD wDeviceNum;
	WORD wMultiSector;
	DWORD dwCapacity;
};

/*
// Type declarations
*/
typedef struct ST_ATAINFO_TAG ST_ATAINFO;

/*
// Variable declarations
*/
static ST_ATAINFO sInfo;
static BYTE bDescriptor[2] = "HD";
#pragma alignvar(4)
/*
// Static function prototype
*/
static void CommandProcess(void *pMcardDev);
static void WaitDelay(WORD wCount);
static void Select(void);
static void DeSelect(void);
static SWORD DmaWaitDataRdy(void);
static SWORD PioWaitDataRdy(void);
static SWORD WaitReady(void);
static DWORD SetParameters(DWORD dwLba, DWORD dwCount);
static void SetCommand(WORD wCommand);
static SWORD SetTransMode(BYTE bMode);
static SWORD PIORead(DWORD dwBuffer, WORD wSectorCnt);
static SWORD PIOWrite(DWORD dwBuffer, WORD wSectorCnt);
static SWORD DMARead(DWORD dwBuffer, WORD wSectorCnt);
static SWORD DMAWrite(DWORD dwBuffer, WORD wSectorCnt);
static SWORD DataRead(DWORD dwBuffer, DWORD dwLba, DWORD dwCount);
static SWORD DataWrite(DWORD dwBuffer, DWORD dwLba, DWORD dwCount);
static BYTE CalBit1(BYTE bValue);
static SWORD Identify(void);
static SWORD PowerOnInit(void);

/*
// Definition of internal functions
*/
void AtaInit(ST_MCARD_DEV * sDev)
{
	sDev->pbDescriptor = bDescriptor;
	sDev->dwLunNum = HD_LUN_NUM;
	sDev->wMcardType = HD;
	sDev->Flag.Installed = 1;
	sDev->CommandProcess = CommandProcess;
}

/*
// Definition of local functions 
*/
static void CommandProcess(void *pMcardDev)
{
	register UART *sUart;
	ST_MCARD_MAIL *sMcardRMail;
	register ST_MCARD_DEV *pDev = ((ST_MCARD_DEV *) pMcardDev);

	sMcardRMail = ((ST_MCARD_DEV *) pMcardDev)->sMcardRMail;
	
	Select();
	switch (sMcardRMail->wCmd)
	{
	case INIT_CARD_CMD:
		
		if (!((ST_MCARD_DEV *) pMcardDev)->Flag.Detected)
		{
			//card in
			((ST_MCARD_DEV *) pMcardDev)->Flag.Detected = 1;
			if ((((ST_MCARD_DEV *) pMcardDev)->swStatus = PowerOnInit()))
			{
					
				((ST_MCARD_DEV *) pMcardDev)->Flag.Detected = 0;
				((ST_MCARD_DEV *) pMcardDev)->Flag.Present = 0;
				((ST_MCARD_DEV *) pMcardDev)->dwCapacity = sInfo.dwCapacity;
				((ST_MCARD_DEV *) pMcardDev)->wSectorSize = MCARD_SECTOR_SIZE;
				//McardSetCurLun(pDev->dwLunNum, NULL_DEVICE);
			}
			else
			{
				((ST_MCARD_DEV *) pMcardDev)->wRenewCounter++;
				((ST_MCARD_DEV *) pMcardDev)->Flag.Present = 1;
				((ST_MCARD_DEV *) pMcardDev)->dwCapacity = sInfo.dwCapacity;
				((ST_MCARD_DEV *) pMcardDev)->wSectorSize = MCARD_SECTOR_SIZE;
				//McardSetCurLun(pDev->dwLunNum, pDev->wMcardType);
				//EventSet(UI_EVENT, EVENT_CARD_INIT);
				
			}
		}
		else
		{
			//card out
			((ST_MCARD_DEV *) pMcardDev)->Flag.Detected = 0;
			((ST_MCARD_DEV *) pMcardDev)->Flag.Present = 0;
			((ST_MCARD_DEV *) pMcardDev)->Flag.ReadOnly = 0;
			((ST_MCARD_DEV *) pMcardDev)->Flag.PipeEnable = 0;
			((ST_MCARD_DEV *) pMcardDev)->swStatus = 0;
			((ST_MCARD_DEV *) pMcardDev)->dwCapacity = 0;
			((ST_MCARD_DEV *) pMcardDev)->wSectorSize = 0;
			McardSetCurLun(pDev->dwLunNum, NULL_DEVICE);
		}
		break;
	case REMOVE_CARD_CMD:		//Athena 03.11.2006 seperate card in & out
		//card out
		((ST_MCARD_DEV *) pMcardDev)->Flag.Detected = 0;
		((ST_MCARD_DEV *) pMcardDev)->Flag.Present = 0;
		((ST_MCARD_DEV *) pMcardDev)->Flag.ReadOnly = 0;
		((ST_MCARD_DEV *) pMcardDev)->Flag.PipeEnable = 0;
		((ST_MCARD_DEV *) pMcardDev)->swStatus = 0;
		((ST_MCARD_DEV *) pMcardDev)->dwCapacity = 0;
		((ST_MCARD_DEV *) pMcardDev)->wSectorSize = 0;
		McardSetCurLun(pDev->dwLunNum, NULL_DEVICE);
		break;
	case READ_PAGE_CMD:
		((ST_MCARD_DEV *) pMcardDev)->swStatus =
			DataRead(sMcardRMail->dwBuffer, sMcardRMail->dwBlockAddr, sMcardRMail->dwBlockCount);
		break;

	case WRITE_PAGE_CMD:
		((ST_MCARD_DEV *) pMcardDev)->swStatus =
			DataWrite(sMcardRMail->dwBuffer, sMcardRMail->dwBlockAddr, sMcardRMail->dwBlockCount);
		break;

	case FORMAT_CMD:
		
	default:
		MP_DEBUG("-E- ATA INVALID CMD");
		break;
	}
	DeSelect();
}

static void WaitDelay(WORD wCount)
{
	WORD i, j;

	for (i = 0; i < wCount; i++)
	{
		for (j = 0; j < 0x80; j++);
	}
}

static void Select(void)
{
	register MCARD *sMcard;
	register GPIO *sGpio;
	register UART *sUart;
	register ATA *sAta;

	sAta = (ATA *) (ATA_BASE);
	McardSetClock(1);//set ata clock as PLL1/4
	sGpio = (GPIO *) (GPIO_BASE);
	///////////////////////////////
	sGpio->Fgpcfg[0] = 0x0000ffff;
	//??sGpio->Fgpcfg[1] &= ~0x06070000;	// config Fgpio[16] as outpt for FPGA bug (control by software)
	//??sGpio->Fgpcfg[1] |= 0x0000607;	// config Fgpio[16] as outpt for FPGA bug (control by software)
	sGpio->Fgpcfg[2] &= ~0x00260000;
	sGpio->Fgpcfg[2] |= 0x00000026;
	sGpio->Fgpcfg[3] &= ~0x00070000;
	sGpio->Fgpcfg[3] |= 0x00000007;

	sGpio->Fgpcfg[0] = 0x0000FFFF;
	sGpio->Fgpcfg[1] = 0x00000607;
	sGpio->Fgpcfg[2] = 0x00004026;
	sGpio->Fgpcfg[3] = 0x00000187;
		

	sMcard = (MCARD *) MCARD_BASE;
	sMcard->McardC = 0x00000100;	// enable ATA module   

	sAta->AtaSta = 0x00000001;
	sAta->AtaSta = 0x00000000;
	sAta->AtaPioTim = 0x00000108;	//12109
	sAta->AtaMdmaTim = 0x00000088;

	sAta->AtaDevice = sInfo.wDeviceNum;
	WaitDelay(5);
}

static void DeSelect(void)
{
	MCARD *sMcard;

	sMcard = (MCARD *) MCARD_BASE;
	sMcard->McardC = 0;
}

static SWORD DmaWaitDataRdy(void)
{
	register ATA *sAta;
	DWORD dwTimeOut;

	sAta = (ATA *) (ATA_BASE);
	dwTimeOut = ATA_TIMEOUT;
	while (dwTimeOut)
	{
		if ((sAta->AtaSta & 0x00000020))	// wait DMARQ
		{
			return PASS;
		}
		WaitDelay(1);
		dwTimeOut--;
	}
	return FAIL;
}

static SWORD PioWaitDataRdy(void)
{
	register ATA *sAta;
	DWORD dwTimeOut;

	sAta = (ATA *) (ATA_BASE);

	dwTimeOut = ATA_TIMEOUT;

	while (dwTimeOut)
	{
		if ((sAta->AtaStatusCommand & 0x8800) == 0x0800)	// wait BSY=0 and DRQ=1
		{
			//MP_DEBUG("PioWaitDataRdy success!!!!!!!!!!!!");
			return PASS;
		}
		WaitDelay(1);
		dwTimeOut--;
	}
	return FAIL;
}


static SWORD WaitReady(void)
{
	register ATA *sAta;
	DWORD dwTimeOut;

	sAta = (ATA *) (ATA_BASE);
	dwTimeOut = ATA_TIMEOUT;
	while (dwTimeOut)
	{
		if (!(sAta->AtaStatusCommand & 0x8000))	// wait BSY=0 and DRQ=0
		{
			return PASS;
		}
		WaitDelay(1);
		dwTimeOut--;
	}
	return FAIL;
}


// Set ATA command register, and return the number of sector read
#if 1
static DWORD SetParameters(DWORD dwLba, DWORD dwCount)
{
	register ATA *sAta;
	DWORD dwTemp;
	BYTE i,j;
	j=1;
	sAta = (ATA *) (ATA_BASE);
	if(dwLba & 0xf0000000)
		j=2;
	for(i=0;i<j;i++)
	{
		if((i==0) && (j==1))
			dwTemp = dwLba;
		else if((i==0) && (j==2))
			dwTemp = (dwLba & 0xff000000)>>24;
		else if((i==1) && (j==2))
			dwTemp = dwLba & 0x00ffffff;	
		
		sAta->AtaLbaL = (dwTemp & 0x000000ff) << 8;
		WaitDelay(1);
		sAta->AtaLbaM = dwTemp & 0x0000ff00;
		WaitDelay(1);
		dwTemp >>= 8;
		sAta->AtaLbaH = dwTemp & 0x0000ff00;
		WaitDelay(1);
		if(!((i==0) && (j==2)))
		{
			dwTemp >>= 8;
			sAta->AtaDevice = (dwTemp & 0x0000ff00) | (sInfo.wDeviceNum);
		
			WaitDelay(1);
			if (dwCount >= 256)
			{
				sAta->AtaSectorCnt = 0;
				return 256;
			}
			else
			{
				sAta->AtaSectorCnt = (BYTE) dwCount << 8;
				return dwCount;
			}
		}
		if((i==0) &&(j==2))
		{
			if(dwCount>=256)	
				sAta->AtaSectorCnt = (0x01<<8);
			else
			sAta->AtaSectorCnt = 0x00;				
		}
	}
}
#else
static DWORD SetParameters(DWORD dwLba, DWORD dwCount)
{
	register ATA *sAta;
	DWORD dwTemp;

	sAta = (ATA *) (ATA_BASE);

	dwTemp = dwLba;
	sAta->AtaLbaL = (dwTemp & 0x000000ff) << 8;
	WaitDelay(1);
	sAta->AtaLbaM = dwTemp & 0x0000ff00;
	WaitDelay(1);
	dwTemp >>= 8;
	sAta->AtaLbaH = dwTemp & 0x0000ff00;
	WaitDelay(1);
	dwTemp >>= 8;
	sAta->AtaDevice = (dwTemp & 0x0000ff00) | (sInfo.wDeviceNum);

	WaitDelay(1);
	if (dwCount >= 256)
	{
		sAta->AtaSectorCnt = 0;
		return 256;
	}
	else
	{
		sAta->AtaSectorCnt = (BYTE) dwCount << 8;
		return dwCount;
	}
}

#endif
static void SetCommand(WORD wCommand)
{
	register ATA *sAta;

	sAta = (ATA *) (ATA_BASE);
	sAta->AtaStatusCommand = wCommand;
	WaitDelay(1);
}


/*
    ATA set transfer mode

*/
static SWORD SetTransMode(BYTE bMode)
{
	register ATA *sAta;
	DWORD dwTemp;

	sAta = (ATA *) ATA_BASE;

	sAta->AtaDevice = sInfo.wDeviceNum;
	WaitDelay(1);
	sAta->AtaErrorFeature = 0x0300;	// set transfer mode subcommand
	WaitDelay(1);
	sAta->AtaSectorCnt = bMode << 8;
	WaitDelay(1);
	SetCommand(ATA_FEATURE_SET);

	WaitDelay(1);

	do
	{
		dwTemp = sAta->AtaStatusCommand;
		WaitDelay(1);
		if (dwTemp & 0x0100)
		{
			MP_DEBUG("Set Trans Mode fail");
			return FAIL;
		}
	}
	while (dwTemp & 0x8000);
	return PASS;
}


static SWORD PIORead(DWORD dwBuffer, WORD wSectorCnt)
{
	register ATA *sAta;
	WORD wTmpSectorCnt;
	WORD *pwTmpBufferC, *pwTmpBufferE;

	sAta = (ATA *) (ATA_BASE);
	pwTmpBufferC = (WORD *) dwBuffer;
	pwTmpBufferE = pwTmpBufferC + 256;
	MP_DEBUG1("PIO read begin %d!!!!!!!",wSectorCnt);
	//TimerDelay(ATA_DELAY);
	for (wTmpSectorCnt = 0; wTmpSectorCnt < wSectorCnt; wTmpSectorCnt++)
	{
	
		if (PioWaitDataRdy() != PASS)
		{
			return FAIL;
		}

		while (pwTmpBufferC < pwTmpBufferE)
		{
			*pwTmpBufferC = (WORD) sAta->AtaData;
			WaitDelay(1);
			pwTmpBufferC++;
		}
		pwTmpBufferE += 256;
	}
	return PASS;
}

static SWORD PIOWrite(DWORD dwBuffer, WORD wSectorCnt)
{
	register ATA *sAta;
	WORD wTmpSectorCnt;
	WORD *pwTmpBufferC, *pwTmpBufferE;

	sAta = (ATA *) (ATA_BASE);
	pwTmpBufferC = (WORD *) dwBuffer;
	pwTmpBufferE = pwTmpBufferC + 256;
	//TimerDelay(ATA_DELAY);
	for (wTmpSectorCnt = 0; wTmpSectorCnt < wSectorCnt; wTmpSectorCnt++)
	{
		if (PioWaitDataRdy() != PASS)
		{
			return FAIL;
		}

		while (pwTmpBufferC < pwTmpBufferE)
		{
			sAta->AtaData = (DWORD) * pwTmpBufferC;
			WaitDelay(1);
			pwTmpBufferC++;
		}
		pwTmpBufferE += 256;
	}
	return PASS;
}


static SWORD DMARead(DWORD dwBuffer, WORD wSectorCnt)
{
	register CHANNEL *sChannel;
	register ATA *sAta;
	register GPIO *sGpio;
	DWORD dwcount = ATA_TIMEOUT;

	sGpio = (GPIO *) (GPIO_BASE);
	//__asm("break 100");
	if (!wSectorCnt)
	{
		UartOutText("DMA

⌨️ 快捷键说明

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