Support for gmini ATA interface
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5622 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
e386d9461c
commit
99e72c8758
1 changed files with 181 additions and 59 deletions
|
@ -47,8 +47,98 @@
|
|||
#define ATA_CONTROL1 ((volatile unsigned char*)0x06200206)
|
||||
#define ATA_CONTROL2 ((volatile unsigned char*)0x06200306)
|
||||
#define ATA_CONTROL (*ata_control)
|
||||
|
||||
#endif
|
||||
|
||||
#if CONFIG_CPU == TCC730
|
||||
|
||||
#define PREFER_C_READING
|
||||
#define PREFER_C_WRITING
|
||||
|
||||
#define ATA_DATA_IDX (0xD0)
|
||||
#define ATA_ERROR_IDX (0xD2)
|
||||
#define ATA_NSECTOR_IDX (0xD4)
|
||||
#define ATA_SECTOR_IDX (0xD6)
|
||||
#define ATA_LCYL_IDX (0xD8)
|
||||
#define ATA_HCYL_IDX (0xDA)
|
||||
#define ATA_SELECT_IDX (0xDC)
|
||||
#define ATA_COMMAND_IDX (0xDE)
|
||||
#define ATA_CONTROL_IDX (0xEC)
|
||||
|
||||
#define ATA_FEATURE_IDX ATA_ERROR_IDX
|
||||
#define ATA_STATUS_IDX ATA_COMMAND_IDX
|
||||
#define ATA_ALT_STATUS_IDX ATA_CONTROL_IDX
|
||||
|
||||
#define SET_REG(reg, value) (ide_write_register(reg, value))
|
||||
#define GET_REG(reg) (ide_read_register(reg))
|
||||
|
||||
#define ATA_DATA (GET_REG(ATA_DATA_IDX))
|
||||
#define ATA_ERROR (GET_REG(ATA_ERROR_IDX))
|
||||
#define ATA_NSECTOR (GET_REG(ATA_NSECTOR_IDX))
|
||||
#define ATA_SECTOR (GET_REG(ATA_SECTOR_IDX))
|
||||
#define ATA_LCYL (GET_REG(ATA_LCYL_IDX))
|
||||
#define ATA_HCYL (GET_REG(ATA_HCYL_IDX))
|
||||
#define ATA_SELECT (GET_REG(ATA_SELECT_IDX))
|
||||
#define ATA_COMMAND (GET_REG(ATA_COMMAND_IDX))
|
||||
|
||||
#define ATA_STATUS (GET_REG(ATA_STATUS_IDX))
|
||||
#define ATA_ALT_STATUS (GET_REG(ATA_ALT_STATUS_IDX))
|
||||
#define ATA_FEATURE (GET_REG(ATA_FEATURE_IDX))
|
||||
|
||||
|
||||
#define SET_ATA_DATA(v) (SET_REG(ATA_DATA_IDX,v))
|
||||
#define SET_ATA_SELECT(v) (SET_REG(ATA_SELECT_IDX,v))
|
||||
#define SET_ATA_NSECTOR(v) (SET_REG(ATA_NSECTOR_IDX,v))
|
||||
#define SET_ATA_SECTOR(v) (SET_REG(ATA_SECTOR_IDX,v))
|
||||
#define SET_ATA_LCYL(v) (SET_REG(ATA_LCYL_IDX,v))
|
||||
#define SET_ATA_HCYL(v) (SET_REG(ATA_HCYL_IDX,v))
|
||||
#define SET_ATA_COMMAND(v) (SET_REG(ATA_COMMAND_IDX,v))
|
||||
#define SET_ATA_CONTROL(v) (SET_REG(ATA_CONTROL_IDX,v))
|
||||
#define SET_ATA_FEATURE(v) (SET_REG(ATA_FEATURE_IDX, v))
|
||||
|
||||
|
||||
extern int idatastart __attribute__ ((section(".idata")));
|
||||
|
||||
static unsigned ide_reg_temp __attribute__ ((section(".idata")));
|
||||
|
||||
void ide_write_register(int reg, int value) {
|
||||
/* Archos firmware code does (sometimes!) this:
|
||||
set the RAM speed to 8 cycles.
|
||||
MIUSCFG |= 0x7;
|
||||
*/
|
||||
|
||||
ide_reg_temp = value;
|
||||
|
||||
long extAddr = (long)reg << 16;
|
||||
ddma_transfer(1, 1, (char*)&ide_reg_temp - (char*)&idatastart, extAddr, 2);
|
||||
|
||||
/* set the RAM speed to 6 cycles.
|
||||
unsigned char miuscfg = MIUSCFG;
|
||||
miuscfg = (miuscfg & ~7) | 5;
|
||||
*/
|
||||
}
|
||||
|
||||
int ide_read_register(int reg) {
|
||||
/* set the RAM speed to 6 cycles.
|
||||
unsigned char miuscfg = MIUSCFG;
|
||||
miuscfg = (miuscfg & ~7) | 5;
|
||||
MIUSCFG = miuscfg; */
|
||||
|
||||
long extAddr = (long)reg << 16;
|
||||
ddma_transfer(0, 1, (char*)&ide_reg_temp - (char*)&idatastart, extAddr, 2);
|
||||
|
||||
/* This is done like this in the archos firmware...
|
||||
miuscfg = MIUSCFG;
|
||||
miuscfg = (miuscfg & ~7) | 5;
|
||||
MIUSCFG = miuscfg;
|
||||
Though I'd expect MIUSCFG &= ~0x7; (1 cycle) */
|
||||
|
||||
return ide_reg_temp;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/* generic registers */
|
||||
#define ATA_ERROR (*((volatile unsigned char*)ATA_IOBASE + 1))
|
||||
#define ATA_NSECTOR (*((volatile unsigned char*)ATA_IOBASE + 2))
|
||||
|
@ -61,6 +151,20 @@
|
|||
#define ATA_STATUS ATA_COMMAND
|
||||
#define ATA_ALT_STATUS ATA_CONTROL
|
||||
|
||||
#define SET_REG(reg, value) ((reg) = (value))
|
||||
|
||||
#define SET_ATA_DATA(v) (SET_REG(ATA_DATA,v))
|
||||
#define SET_ATA_SELECT(v) (SET_REG(ATA_SELECT,v))
|
||||
#define SET_ATA_NSECTOR(v) (SET_REG(ATA_NSECTOR,v))
|
||||
#define SET_ATA_SECTOR(v) (SET_REG(ATA_SECTOR,v))
|
||||
#define SET_ATA_LCYL(v) (SET_REG(ATA_LCYL,v))
|
||||
#define SET_ATA_HCYL(v) (SET_REG(ATA_HCYL,v))
|
||||
#define SET_ATA_COMMAND(v) (SET_REG(ATA_COMMAND,v))
|
||||
#define SET_ATA_CONTROL(v) (SET_REG(ATA_CONTROL,v))
|
||||
#define SET_ATA_FEATURE(v) (SET_REG(ATA_FEATURE, v))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define SELECT_DEVICE1 0x10
|
||||
|
@ -181,7 +285,11 @@ static int wait_for_end_of_transfer(void)
|
|||
return (ATA_ALT_STATUS & (STATUS_RDY|STATUS_DRQ)) == STATUS_RDY;
|
||||
}
|
||||
|
||||
|
||||
/* Optimization: don't do 256 calls to ddma_transfer; fuse with it
|
||||
* as in the Archos firmware.
|
||||
* It actually possible to do a single dma transfer to copy a whole sector between ATA
|
||||
* controller & cpu internal memory.
|
||||
*/
|
||||
/* the tight loop of ata_read_sectors(), to avoid the whole in IRAM */
|
||||
static void copy_read_sectors(unsigned char* buf,
|
||||
int wordcount)
|
||||
|
@ -351,7 +459,7 @@ int ata_read_sectors(IF_MV2(int drive,)
|
|||
|
||||
timeout = current_tick + READ_TIMEOUT;
|
||||
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT(ata_device);
|
||||
if (!wait_for_rdy())
|
||||
{
|
||||
mutex_unlock(&ata_mtx);
|
||||
|
@ -367,22 +475,22 @@ int ata_read_sectors(IF_MV2(int drive,)
|
|||
last_disk_activity = current_tick;
|
||||
|
||||
if ( count == 256 )
|
||||
ATA_NSECTOR = 0; /* 0 means 256 sectors */
|
||||
SET_ATA_NSECTOR(0); /* 0 means 256 sectors */
|
||||
else
|
||||
ATA_NSECTOR = (unsigned char)count;
|
||||
SET_ATA_NSECTOR((unsigned char)count);
|
||||
|
||||
ATA_SECTOR = start & 0xff;
|
||||
ATA_LCYL = (start >> 8) & 0xff;
|
||||
ATA_HCYL = (start >> 16) & 0xff;
|
||||
ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA | ata_device;
|
||||
ATA_COMMAND = CMD_READ_MULTIPLE;
|
||||
SET_ATA_SECTOR(start & 0xff);
|
||||
SET_ATA_LCYL((start >> 8) & 0xff);
|
||||
SET_ATA_HCYL((start >> 16) & 0xff);
|
||||
SET_ATA_SELECT(((start >> 24) & 0xf) | SELECT_LBA | ata_device);
|
||||
SET_ATA_COMMAND(CMD_READ_MULTIPLE);
|
||||
|
||||
/* wait at least 400ns between writing command and reading status */
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
asm volatile ("nop");
|
||||
__asm__ volatile ("nop");
|
||||
__asm__ volatile ("nop");
|
||||
__asm__ volatile ("nop");
|
||||
__asm__ volatile ("nop");
|
||||
__asm__ volatile ("nop");
|
||||
|
||||
while (count) {
|
||||
int sectors;
|
||||
|
@ -480,7 +588,7 @@ static void copy_write_sectors(const unsigned char* buf, int wordcount)
|
|||
/* takes 13 clock cycles (2 pipeline stalls) */
|
||||
tmp = (unsigned short) *buf++;
|
||||
tmp |= (unsigned short) *buf++ << 8; /* I assume big endian */
|
||||
ATA_DATA = tmp; /* and don't use the SWAB16 macro */
|
||||
SET_ATA_DATA(tmp); /* and don't use the SWAB16 macro */
|
||||
} while (buf < bufend); /* tail loop is faster */
|
||||
}
|
||||
else
|
||||
|
@ -490,7 +598,7 @@ static void copy_write_sectors(const unsigned char* buf, int wordcount)
|
|||
do
|
||||
{ /* loop compiles to 6 assembler instructions */
|
||||
/* takes 10 clock cycles (2 pipeline stalls) */
|
||||
ATA_DATA = SWAB16(*wbuf);
|
||||
SET_ATA_DATA(SWAB16(*wbuf));
|
||||
} while (++wbuf < wbufend); /* tail loop is faster */
|
||||
}
|
||||
#else
|
||||
|
@ -620,7 +728,7 @@ int ata_write_sectors(IF_MV2(int drive,)
|
|||
}
|
||||
}
|
||||
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT(ata_device);
|
||||
if (!wait_for_rdy())
|
||||
{
|
||||
mutex_unlock(&ata_mtx);
|
||||
|
@ -629,14 +737,14 @@ int ata_write_sectors(IF_MV2(int drive,)
|
|||
}
|
||||
|
||||
if ( count == 256 )
|
||||
ATA_NSECTOR = 0; /* 0 means 256 sectors */
|
||||
SET_ATA_NSECTOR(0); /* 0 means 256 sectors */
|
||||
else
|
||||
ATA_NSECTOR = (unsigned char)count;
|
||||
ATA_SECTOR = start & 0xff;
|
||||
ATA_LCYL = (start >> 8) & 0xff;
|
||||
ATA_HCYL = (start >> 16) & 0xff;
|
||||
ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA | ata_device;
|
||||
ATA_COMMAND = CMD_WRITE_SECTORS;
|
||||
SET_ATA_NSECTOR((unsigned char)count);
|
||||
SET_ATA_SECTOR(start & 0xff);
|
||||
SET_ATA_LCYL((start >> 8) & 0xff);
|
||||
SET_ATA_HCYL((start >> 16) & 0xff);
|
||||
SET_ATA_SELECT(((start >> 24) & 0xf) | SELECT_LBA | ata_device);
|
||||
SET_ATA_COMMAND(CMD_WRITE_SECTORS);
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
|
||||
|
@ -663,8 +771,10 @@ int ata_write_sectors(IF_MV2(int drive,)
|
|||
last_disk_activity = current_tick;
|
||||
}
|
||||
|
||||
if(!ret && !wait_for_end_of_transfer())
|
||||
if(!ret && !wait_for_end_of_transfer()) {
|
||||
DEBUGF("End on transfer failed. -- jyp");
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
led(false);
|
||||
|
||||
|
@ -700,19 +810,22 @@ extern void ata_flush(void)
|
|||
|
||||
static int check_registers(void)
|
||||
{
|
||||
int i;
|
||||
if ( ATA_STATUS & STATUS_BSY )
|
||||
return -1;
|
||||
|
||||
ATA_NSECTOR = 0xa5;
|
||||
ATA_SECTOR = 0x5a;
|
||||
ATA_LCYL = 0xaa;
|
||||
ATA_HCYL = 0x55;
|
||||
for (i = 0; i<64; i++) {
|
||||
SET_ATA_NSECTOR ( 0xa5);
|
||||
SET_ATA_SECTOR ( 0x5a);
|
||||
SET_ATA_LCYL ( 0xaa);
|
||||
SET_ATA_HCYL ( 0x55);
|
||||
|
||||
if ((ATA_NSECTOR == 0xa5) &&
|
||||
(ATA_SECTOR == 0x5a) &&
|
||||
(ATA_LCYL == 0xaa) &&
|
||||
(ATA_HCYL == 0x55))
|
||||
if ((ATA_NSECTOR == 0xa5) &&
|
||||
(ATA_SECTOR == 0x5a) &&
|
||||
(ATA_LCYL == 0xaa) &&
|
||||
(ATA_HCYL == 0x55))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
@ -722,12 +835,12 @@ static int freeze_lock(void)
|
|||
/* does the disk support Security Mode feature set? */
|
||||
if (identify_info[82] & 2)
|
||||
{
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT (ata_device);
|
||||
|
||||
if (!wait_for_rdy())
|
||||
return -1;
|
||||
|
||||
ATA_COMMAND = CMD_SECURITY_FREEZE_LOCK;
|
||||
SET_ATA_COMMAND(CMD_SECURITY_FREEZE_LOCK);
|
||||
|
||||
if (!wait_for_rdy())
|
||||
return -2;
|
||||
|
@ -762,7 +875,7 @@ static int ata_perform_sleep(void)
|
|||
|
||||
mutex_lock(&ata_mtx);
|
||||
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT(ata_device);
|
||||
|
||||
if(!wait_for_rdy()) {
|
||||
DEBUGF("ata_perform_sleep() - not RDY\n");
|
||||
|
@ -770,7 +883,7 @@ static int ata_perform_sleep(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
ATA_COMMAND = CMD_SLEEP;
|
||||
SET_ATA_COMMAND(CMD_SLEEP);
|
||||
|
||||
if (!wait_for_rdy())
|
||||
{
|
||||
|
@ -789,7 +902,7 @@ int ata_standby(int time)
|
|||
|
||||
mutex_lock(&ata_mtx);
|
||||
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT(ata_device);
|
||||
|
||||
if(!wait_for_rdy()) {
|
||||
DEBUGF("ata_standby() - not RDY\n");
|
||||
|
@ -798,11 +911,11 @@ int ata_standby(int time)
|
|||
}
|
||||
|
||||
if(time)
|
||||
ATA_NSECTOR = ((time + 5) / 5) & 0xff; /* Round up to nearest 5 secs */
|
||||
SET_ATA_NSECTOR ( ((time + 5) / 5) & 0xff); /* Round up to nearest 5 secs */
|
||||
else
|
||||
ATA_NSECTOR = 0; /* Disable standby */
|
||||
SET_ATA_NSECTOR ( 0); /* Disable standby */
|
||||
|
||||
ATA_COMMAND = CMD_STANDBY;
|
||||
SET_ATA_COMMAND(CMD_STANDBY);
|
||||
|
||||
if (!wait_for_rdy())
|
||||
{
|
||||
|
@ -899,7 +1012,7 @@ int ata_hard_reset(void)
|
|||
#endif
|
||||
|
||||
/* state HRR2 */
|
||||
ATA_SELECT = ata_device; /* select the right device */
|
||||
SET_ATA_SELECT(ata_device); /* select the right device */
|
||||
ret = wait_for_bsy();
|
||||
|
||||
/* Massage the return code so it is 0 on success and -1 on failure */
|
||||
|
@ -913,11 +1026,11 @@ static int perform_soft_reset(void)
|
|||
int ret;
|
||||
int retry_count;
|
||||
|
||||
ATA_SELECT = SELECT_LBA | ata_device;
|
||||
ATA_CONTROL = CONTROL_nIEN|CONTROL_SRST;
|
||||
SET_ATA_SELECT ( SELECT_LBA | ata_device );
|
||||
SET_ATA_CONTROL ( CONTROL_nIEN|CONTROL_SRST );
|
||||
sleep(1); /* >= 5us */
|
||||
|
||||
ATA_CONTROL = CONTROL_nIEN;
|
||||
SET_ATA_CONTROL (CONTROL_nIEN);
|
||||
sleep(1); /* >2ms */
|
||||
|
||||
/* This little sucker can take up to 30 seconds */
|
||||
|
@ -969,14 +1082,14 @@ static int ata_power_on(void)
|
|||
static int master_slave_detect(void)
|
||||
{
|
||||
/* master? */
|
||||
ATA_SELECT = 0;
|
||||
SET_ATA_SELECT( 0 );
|
||||
if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
|
||||
ata_device = 0;
|
||||
DEBUGF("Found master harddisk\n");
|
||||
}
|
||||
else {
|
||||
/* slave? */
|
||||
ATA_SELECT = SELECT_DEVICE1;
|
||||
SET_ATA_SELECT( SELECT_DEVICE1 );
|
||||
if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
|
||||
ata_device = SELECT_DEVICE1;
|
||||
DEBUGF("Found slave harddisk\n");
|
||||
|
@ -1022,14 +1135,15 @@ static int identify(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT ( ata_device );
|
||||
|
||||
if(!wait_for_rdy()) {
|
||||
DEBUGF("identify() - not RDY\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ATA_COMMAND = CMD_IDENTIFY;
|
||||
|
||||
SET_ATA_COMMAND ( CMD_IDENTIFY );
|
||||
|
||||
if (!wait_for_start_of_transfer())
|
||||
{
|
||||
|
@ -1037,6 +1151,7 @@ static int identify(void)
|
|||
return -2;
|
||||
}
|
||||
|
||||
|
||||
for (i=0; i<SECTOR_SIZE/2; i++)
|
||||
/* the IDENTIFY words are already swapped */
|
||||
identify_info[i] = ATA_DATA;
|
||||
|
@ -1046,15 +1161,15 @@ static int identify(void)
|
|||
|
||||
static int set_multiple_mode(int sectors)
|
||||
{
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT ( ata_device );
|
||||
|
||||
if(!wait_for_rdy()) {
|
||||
DEBUGF("set_multiple_mode() - not RDY\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ATA_NSECTOR = sectors;
|
||||
ATA_COMMAND = CMD_SET_MULTIPLE_MODE;
|
||||
SET_ATA_NSECTOR ( sectors );
|
||||
SET_ATA_COMMAND ( CMD_SET_MULTIPLE_MODE );
|
||||
|
||||
if (!wait_for_rdy())
|
||||
{
|
||||
|
@ -1092,7 +1207,7 @@ static int set_features(void)
|
|||
/* Update the table */
|
||||
features[3].parameter = 8 + pio_mode;
|
||||
|
||||
ATA_SELECT = ata_device;
|
||||
SET_ATA_SELECT( ata_device );
|
||||
|
||||
if (!wait_for_rdy()) {
|
||||
DEBUGF("set_features() - not RDY\n");
|
||||
|
@ -1101,9 +1216,9 @@ static int set_features(void)
|
|||
|
||||
for (i=0; features[i].id_word; i++) {
|
||||
if (identify_info[features[i].id_word] & (1 << features[i].id_bit)) {
|
||||
ATA_FEATURE = features[i].subcommand;
|
||||
ATA_NSECTOR = features[i].parameter;
|
||||
ATA_COMMAND = CMD_SET_FEATURES;
|
||||
SET_ATA_FEATURE ( features[i].subcommand );
|
||||
SET_ATA_NSECTOR ( features[i].parameter );
|
||||
SET_ATA_COMMAND ( CMD_SET_FEATURES );
|
||||
|
||||
if (!wait_for_rdy()) {
|
||||
DEBUGF("set_features() - CMD failed\n");
|
||||
|
@ -1156,7 +1271,12 @@ static int init_and_check(bool hard_reset)
|
|||
int ata_init(void)
|
||||
{
|
||||
int rc;
|
||||
#if CONFIG_CPU == TCC730
|
||||
/* TODO: check for cold start (never happenning now) */
|
||||
bool coldstart = false;
|
||||
#else
|
||||
bool coldstart = (PACR2 & 0x4000) != 0;
|
||||
#endif
|
||||
|
||||
mutex_init(&ata_mtx);
|
||||
|
||||
|
@ -1214,6 +1334,8 @@ int ata_init(void)
|
|||
create_thread(ata_thread, ata_stack,
|
||||
sizeof(ata_stack), ata_thread_name);
|
||||
initialized = true;
|
||||
|
||||
|
||||
}
|
||||
rc = set_multiple_mode(multisectors);
|
||||
if (rc)
|
||||
|
|
Loading…
Reference in a new issue