diff options
author | Jean-Philippe Bernardy <jeanphilippe.bernardy@gmail.com> | 2005-01-20 23:00:11 +0000 |
---|---|---|
committer | Jean-Philippe Bernardy <jeanphilippe.bernardy@gmail.com> | 2005-01-20 23:00:11 +0000 |
commit | 99e72c87584524a40a3020b8e8d9b7f7dbe91ac2 (patch) | |
tree | cc246707706c275ae3bc1433044925b1683a3b58 /firmware/drivers | |
parent | e386d9461c8394ef653c0e87caa1d4b8d2c588ab (diff) |
Support for gmini ATA interface
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5622 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/ata.c | 240 |
1 files changed, 181 insertions, 59 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index bd1afec2d9..ae202e803a 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c @@ -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 @@ -147,7 +251,7 @@ static int wait_for_rdy(void) __attribute__ ((section (".icode"))); static int wait_for_rdy(void) { int timeout; - + if (!wait_for_bsy()) return 0; @@ -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; - - if ((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)) 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); @@ -1199,7 +1319,7 @@ int ata_init(void) return -40 + rc; multisectors = identify_info[47] & 0xff; DEBUGF("ata: %d sectors per ata request\n",multisectors); - + rc = freeze_lock(); if (rc) return -50 + rc; @@ -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) |