📄 ata.c
字号:
#include "system.h"
#include "etc.h"
#include "ata.h"
#define PERF_TEST_ATA 0 // overall time
#define PERF_TEST_PIO_D 0 // only data transfering time
#define PERF_TEST_UDMA_D 0 // only data transfering time
#define DBG_ATA 1
#if DBG_ATA
#define DbgAta(x) printf x
#else
#define DbgAta(x) 0;
#endif
#define CFCON_BASE 0x4B800000
#ifdef CFCON_MODE
#define ATA_MUX (CFCON_BASE+0x1800)
#define ATA_BASE (CFCON_BASE+0x1900)
#endif
/*--------------------------------------------------------------*/
/* ATA Register */
/*--------------------------------------------------------------*/
#define ATA_CONTROL (ATA_BASE + 0x00) //ATA0 enable and clock down status
#define ATA_STATUS (ATA_BASE + 0x04) //ATA0 status
#define ATA_COMMAND (ATA_BASE + 0x08) //ATA0 command
#define ATA_SWRST (ATA_BASE + 0x0C) //ATA0 software reset
#define ATA_IRQ (ATA_BASE + 0x10) //ATA0 interrupt sources
#define ATA_IRQ_MASK (ATA_BASE + 0x14) //ATA0 interrupt mask
#define ATA_CFG (ATA_BASE + 0x18) //ATA0 configuration for ATA interface
#define ATA_PIO_TIME (ATA_BASE + 0x2C) //ATA0 PIO timing
#define ATA_UDMA_TIME (ATA_BASE + 0x30) //ATA0 UDMA timing
#define ATA_XFR_NUM (ATA_BASE + 0x34) //ATA0 transfer number
#define ATA_XFR_CNT (ATA_BASE + 0x38) //ATA0 current transfer count
#define ATA_TBUF_START (ATA_BASE + 0x3C) //ATA0 start address of track buffer
#define ATA_TBUF_SIZE (ATA_BASE + 0x40) //ATA0 size of track buffer
#define ATA_SBUF_START (ATA_BASE + 0x44) //ATA0 start address of Source buffer1
#define ATA_SBUF_SIZE (ATA_BASE + 0x48) //ATA0 size of source buffer1
#define ATA_CADR_TBUF (ATA_BASE + 0x4C) //ATA0 current write address of track buffer
#define ATA_CADR_SBUF (ATA_BASE + 0x50) //ATA0 current read address of source buffer
#define ATA_PIO_DTR (ATA_BASE + 0x54) //ATA0 PIO device data register
#define ATA_PIO_FED (ATA_BASE + 0x58) //ATA0 PIO device Feature/Error register
#define ATA_PIO_SCR (ATA_BASE + 0x5C) //ATA0 PIO sector count register
#define ATA_PIO_LLR (ATA_BASE + 0x60) //ATA0 PIO device LBA low register
#define ATA_PIO_LMR (ATA_BASE + 0x64) //ATA0 PIO device LBA middle register
#define ATA_PIO_LHR (ATA_BASE + 0x68) //ATA0 PIO device LBA high register
#define ATA_PIO_DVR (ATA_BASE + 0x6C) //ATA0 PIO device register
#define ATA_PIO_CSD (ATA_BASE + 0x70) //ATA0 PIO device command/status register
#define ATA_PIO_DAD (ATA_BASE + 0x74) //ATA0 PIO device control/alternate status register
#define ATA_PIO_READY (ATA_BASE + 0x78) //ATA0 PIO data read/write ready
#define ATA_PIO_RDATA (ATA_BASE + 0x7C) //ATA0 PIO read data from device data register
#define BUS_FIFO_STATUS (ATA_BASE + 0x90) //Internal AHBP fifo status
#define ATA_FIFO_STATUS (ATA_BASE + 0x94) //Internal ATA0 fifo status
/*=========================================================================
* ata Register Address
*=========================================================================
*/
#define DEV_ERROR (ATA_BASE + 0x58)
#define DEV_FEATURE (ATA_BASE + 0x58)
#define DEV_SECTOR (ATA_BASE + 0x5c)
#define DEV_LOWLBA (ATA_BASE + 0x60)
#define DEV_MIDLBA (ATA_BASE + 0x64)
#define DEV_HIGHLBA (ATA_BASE + 0x68)
#define DEV_DEVICE (ATA_BASE + 0x6c)
#define DEV_STATUS (ATA_BASE + 0x70)
#define DEV_COMMAND (ATA_BASE + 0x70)
#define DEV_ALTANATE (ATA_BASE + 0x74)
#define DEV_CONTROL (ATA_BASE + 0x74)
/*=========================================================================
* ata Command
*=========================================================================
*/
#define IDENTIFYDEVICE 0xec
#define READSECTOR 0x20
#define READMULTIPLE 0xc4
#define READDMA 0xc8
#define WRITESECTOR 0x30
#define WRITEMULTIPLE 0xc5
#define WRITEDMA 0xca
#define SETFEATURES 0xEF
//-------------------------------------------------------------------------
#define ATAPI_MASK 0xffffffe0
#define ATA_SECTORSIZE 512
#define STATUS_DEVICE_BUSY 0x80
#define STATUS_DATA_REQUEST 0x58
#define STATUS_ERR 0x1
// only for SMDK b'd
void SetBufferDirection(unsigned int dir); // 060822
void InitBufferControl(void); // 060902
void ChangeBufferControl(ATA_MODE mode); // 060902
unsigned int uCfgReg;
ATA_MODE eMode;
unsigned int uMaxMultiple;
unsigned int uCurrentMultiple;
unsigned int uMaxSectors;
PIOMODE eMaxPioMode;
PIOMODE eCurrentPioMode;
unsigned int uMaxUdmaMode;
unsigned int uCurrentUdmaMode;
/*=========================================================================
* ata controller register functions
*=========================================================================
*/
void SetAtaOnOff(unsigned char OnOff)
{
unsigned int temp;
Inp32(ATA_CONTROL, temp);
if(OnOff==1)
Outp32(ATA_CONTROL, temp | 0x1);
else if(OnOff == 0)
Outp32(ATA_CONTROL, temp &0xfffffffe);
}
void SetLittleEndian(void)
{
// set Little endian
uCfgReg &= (~0x40);
Outp32(ATA_CFG, uCfgReg);
}
void SetTransferCommand(ATA_TRANSFER_CMD command)
{
unsigned char cmd = (command == ATA_CMD_STOP) ? 0 :
(command == ATA_CMD_START) ? 1 :
(command == ATA_CMD_ABORT) ? 2 : 3;
WaitForHostReady(); /// needed
Outp32(ATA_COMMAND, cmd);
}
void IsTBufFullContinue(bool* status)
{
unsigned int temp;
Inp32(ATA_CFG, temp);
*status = (temp&0x80) ? TRUE : FALSE;
}
void IsSBufEmptyContinue(bool* status)
{
unsigned int temp;
Inp32(ATA_CFG, temp);
*status = (temp&0x100) ? TRUE : FALSE;
}
/*=========================================================================
* ata controller register I/O fuctions
*=========================================================================
*/
void WaitForHostReady(void)
{
unsigned int tempRead;
do {
Inp32(ATA_FIFO_STATUS, tempRead); // modified by Bryan W. Lee (Oct.19th, 2005)
} while((tempRead>>28)!=0);
}
void ReadDeviceReg(unsigned int nRegister, unsigned char* data)
{
unsigned int tempRead;
WaitForHostReady();
Inp32(nRegister, tempRead);
WaitForHostReady();
Inp32(ATA_PIO_RDATA, tempRead);
*data = (unsigned char )(tempRead&0xFF);
}
void GetDataFromDevice(unsigned short* data)
{
unsigned int tempRead;
WaitForHostReady();
Inp32(ATA_PIO_DTR, tempRead);
WaitForHostReady();
Inp32(ATA_PIO_RDATA, tempRead);
*data = (unsigned short)(tempRead&0xFFFF);
}
void WriteOnTaskFileReg(unsigned int nRegister,unsigned int nValue)
{
WaitForHostReady();
Outp32(nRegister, nValue);
}
void PutDataToDevice(unsigned short data)
{
WaitForHostReady();
Outp32(ATA_PIO_DTR, data);
}
void WaitForTransferDone(void)
{
unsigned int x;
do {
WaitForHostReady(); /// needed
Inp32(ATA_STATUS, x);
} while((x & 3)!=0);
}
bool WaitForDeviceReady(void)
{
unsigned char tempRead;
DbgAta(("\n"));
while(1)
{
ReadDeviceReg(DEV_ALTANATE, &tempRead);
ReadDeviceReg(DEV_STATUS, &tempRead);
DbgAta(("[DS:0x%x] ",tempRead));
if((tempRead&STATUS_DEVICE_BUSY) == 0)
break;
}
DbgAta(("\n"));
return TRUE;
}
void Clear_Pending(unsigned int srcInt)
{
// Assert(srcInt < SRC_INT_NUM);
Outp32(ATA_IRQ, (1<<srcInt));
}
bool FindInterruptRequest(unsigned int* nthBit)
{
unsigned int i, temp1, temp2;
for(i=0;i<SRC_INT_NUM;i++) {
Inp32(ATA_IRQ, temp1);
Inp32(ATA_IRQ_MASK, temp2);
if(((temp1&(~temp2))>>i)&0x01)
break;
}
*nthBit = i;
if (i == SRC_INT_NUM)
return FALSE;
else
return TRUE;
}
void ClearAllInterrupt(void)
{
Outp32(ATA_IRQ, 0xff);
Outp32(ATA_IRQ_MASK, ATAPI_MASK|(1<<ATA_INT_IRQ));
}
/*=========================================================================
* FIU BASIC routine
*=========================================================================
*/
void ResetAll(void )
{
// TDelay timer setting
SetResTDelay(10); // TDelay 1 unit = 10us
InitTDelayFunc();
TDelay(203); // 2ms+25us
Outp32(ATA_SWRST, 0x1); // CF controller reset
TDelay(1); // need 5us
Outp32(ATA_SWRST, 0x0);
TDelay(200); // need 2ms
Outp32(ATA_CFG, 0x1); // ata device reset.
TDelay(1);
Outp32(ATA_CFG, 0x0); // ata device no reset.
TDelay(25000); // need 200ms
}
void Init(void)
{
// TDelay timer setting
SetResTDelay(10); // TDelay 1 unit = 10us
InitTDelayFunc();
// GPIO, EBI setting
rEBICON |= (1<<10)|(1<<9); // bank3_cfg->CF,bank2_cfg->CF
rGPGCON |= (3<<30)|(3<<28)|(3<<26)|(3<<24)|(3<<22); //nCARD_PWREN, RESET_CF,nRE3G_CF,nINPACK,nIREQ_CF
#ifdef __EVT1
rGPACDH = 0x1aa8a; // GPA10 RDATA_OEN setting
#else
rGPACON |= (1<<27)|(1<<11)|(1<<14)|(1<<13);// nWE_CF,nOE_CF,nRCS3,nRCS2 enable //S3C2443X01
#endif
rMISCCR &=(~(1<<30)); // card detect when card is detected ,the bit should be '0'.
// Buffer direction mode setting for SMDK2443 060902
InitBufferControl();
ChangeBufferControl(PIO_CPU);
// CF controller - True IDE mode setting
Outp32(ATA_MUX, 0x07); // Output pad disable, Card power off, ATA mode
TDelay(100);
Outp32(ATA_MUX, 0x03); // Output pad enable, Card power off, ATA mode
TDelay(100);
Outp32(ATA_MUX, 0x01); // Output pad enable, Card power on, ATA mode
TDelay(40000); // wait for 500ms, be positively necessary
// Card configuration
Outp32(ATA_PIO_TIME, 0x1C238);
Outp32(ATA_UDMA_TIME, 0x20B1362);
SetLittleEndian();
SetAtaOnOff(1);
TDelay(20000); // wait for 200ms, be positively necessary
uCfgReg = 0; // configuration register value
}
void IdentifyDevice(void)
{
unsigned short readBuffer[ATA_SECTORSIZE/2];
unsigned char tempBuffer;
volatile unsigned char *tempString;
unsigned int tBuf[4];
int i;
for (i=0;i<ATA_SECTORSIZE/2;i++)
readBuffer[i] = 1;
uCfgReg |= 0x40; // set Big endian (must be)
Outp32(ATA_CFG, uCfgReg);
Outp32(ATA_IRQ_MASK, 0xffffffff);
WriteOnTaskFileReg(DEV_DEVICE, 0x40);
WriteOnTaskFileReg(DEV_COMMAND, IDENTIFYDEVICE);
WaitForDeviceReady();
printf("\n");
for(i=0; i<ATA_SECTORSIZE/2; i++) {
GetDataFromDevice(&readBuffer[i]);
printf("(DATA:0x%04X) ",readBuffer[i]);
}
printf("\n");
WaitForDeviceReady();
//
//verify identify data~~~~~~~~~~~~~~~~~~~~~~~~~~
//
tempString = (unsigned char *)&readBuffer[10];
printf("\nSerial Number :");
for(i=0;i<20;i++) printf("%c",*(tempString+i));
tempString = (unsigned char *)&readBuffer[27];
printf("\nModel Number :");
for(i=0;i<40;i++) printf("%c",*(tempString+i));
tBuf[0] = (unsigned char)(readBuffer[61]&0xff);
tBuf[1] = (unsigned char)((readBuffer[61]&0xff00)>>8);
tBuf[2] = (unsigned char)(readBuffer[60]&0xff);
tBuf[3] = (unsigned char)((readBuffer[60]&0xff00)>>8);
uMaxSectors = (unsigned int)((tBuf[0]<<24)|(tBuf[1]<<16)|(tBuf[2]<<8)|tBuf[3]);
printf("\nMax Sectors : %d\n",uMaxSectors);
// Caution: readBuffer[x] - Big Endian, so upper byte means LSB..
uMaxMultiple= (readBuffer[47]>>8)&0xFF;
printf("\nMax Multiple : %02X\n",uMaxMultiple);
if (readBuffer[59]&0x1) { //multiple sector setting is valid
uCurrentMultiple= (readBuffer[59]>>8)&0xFF;
printf("Current Multiple : %03X\n",uCurrentMultiple);
}
if ((readBuffer[64]>>8)&0x3 == 1) eMaxPioMode = PIO3;
else if ((readBuffer[64]>>8)&0x3 == 3) eMaxPioMode = PIO4;
else eMaxPioMode = PIO2;
printf("Max PIO Mode : %d\n",eMaxPioMode);
uMaxUdmaMode =0;
tempBuffer = readBuffer[88]>>8;
for(i=4;i>=0;i--) {
if(tempBuffer&(0x01<<i)) {
uMaxUdmaMode = i;
break;
}
}
uCurrentUdmaMode =0;
tempBuffer = readBuffer[88]&0x00ff;
for(i=0;i<5;i++) {
if(tempBuffer&(0x01<<i)) {
uCurrentUdmaMode = i;
break; ///
}
}
printf("Max UDMA Mode : %d\n", uMaxUdmaMode);
printf("Current UDMA Mode : %d\n", uCurrentUdmaMode);
//
//verify identify data~~~~~~~~~~~~~~~~~~~~~~~END
//
SetLittleEndian();
}
void GetMaxSectors(unsigned int* maxSec)
{
*maxSec = uMaxSectors;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -