From 99e72c87584524a40a3020b8e8d9b7f7dbe91ac2 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bernardy Date: Thu, 20 Jan 2005 23:00:11 +0000 Subject: Support for gmini ATA interface git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5622 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/ata.c | 240 +++++++++++++++++++++++++++++++++++++------------ 1 file 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= 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