diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-10-14 18:09:17 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-10-17 20:30:37 -0400 |
commit | 563da701396c846a555c179308fb4180f2e61d06 (patch) | |
tree | 0b970e33356e899c6b699616d47cc78a1822dc30 | |
parent | 9efed5542eec51b9d963ca41e6b028810f8e26ad (diff) | |
download | rockbox-563da70139.tar.gz rockbox-563da70139.zip |
ipod6g: Reworking the bespoke ATA driver
ipod6g was configured with SECTOR_SIZE of 4096, but this ATA driver
unconditionally translated these to 512B operations on the actual
storage device.
Rockbox's storage layer already has robust support for "logical sectors
larger than physical storage sectors" through use of
MAX_LOG_SECTOR_SIZE. So switch to that mechanism, allowing the ipod6g
ATA driver to be simplified.
If we want to support drives with physical sector sizes > 512B, then
we need to port the MAX_PHYS_SECTOR_SIZE logic from the primary ATA driver.
Additional changes:
* Simplify MWDMA/UDMA selection logic
* Report CE-ATA mode in debug menu
* Use LBA48 commands only if drive is over 128GiB.
* Drop default sleep/poweroff time from 20s to 7s (matching main ATA driver)
Finally, the bulk of the changes are the first phase of a badly needed
style cleanup that made reading this driver a lot harder than it should
be. I intend to split this into a separate patch.
Change-Id: I2feca9fd319c8d6cfb3c2610208970428d2fa947
-rw-r--r-- | apps/debug_menu.c | 13 | ||||
-rw-r--r-- | firmware/drivers/ata.c | 19 | ||||
-rw-r--r-- | firmware/export/config/ipod6g.h | 15 | ||||
-rw-r--r-- | firmware/export/config/vibe500.h | 11 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | 418 |
5 files changed, 277 insertions, 199 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 6cc65c83a4..427df27e3e 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -1430,11 +1430,13 @@ static int disk_callback(int btn, struct gui_synclist *lists) simplelist_addline( "Firmware: %s", buf); - uint64_t total_sectors = identify_info[60] | ((uint32_t)identify_info[61] << 16); + uint64_t total_sectors = (identify_info[61] << 16) | identify_info[60]; #ifdef HAVE_LBA48 - if (identify_info[83] & 0x0400 - && total_sectors == 0x0FFFFFFF) - total_sectors = identify_info[100] | ((uint64_t)identify_info[101] << 16) | ((uint64_t)identify_info[102] << 32) | ((uint64_t)identify_info[103] << 48); + if (identify_info[83] & 0x0400 && total_sectors == 0x0FFFFFFF) + total_sectors = ((uint64_t)identify_info[103] << 48) | + ((uint64_t)identify_info[102] << 32) | + ((uint64_t)identify_info[101] << 16) | + identify_info[100]; #endif uint32_t sector_size; @@ -1555,6 +1557,9 @@ static int disk_callback(int btn, struct gui_synclist *lists) if (i == 0) { simplelist_addline( "DMA not enabled"); + } else if (i == 0xff) { + simplelist_addline( + "CE-ATA mode"); } else { simplelist_addline( "DMA mode: %s %c", diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 525451ff1c..5331e7f589 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c @@ -114,7 +114,6 @@ static int multisectors; /* number of supported multisectors */ static unsigned short identify_info[ATA_IDENTIFY_WORDS]; #ifdef MAX_PHYS_SECTOR_SIZE - struct sector_cache_entry { bool inuse; sector_t sectornum; /* logical sector */ @@ -1068,7 +1067,7 @@ static int set_multiple_mode(int sectors) } #ifdef HAVE_ATA_DMA -static int get_best_mode(unsigned short identword, int max, int modetype) +static int ata_get_best_mode(unsigned short identword, int max, int modetype) { unsigned short testbit = BIT_N(max); @@ -1118,12 +1117,12 @@ static int set_features(void) #ifdef HAVE_ATA_DMA if (identify_info[53] & (1<<2)) { /* Ultra DMA mode info present, find a mode */ - dma_mode = get_best_mode(identify_info[88], ATA_MAX_UDMA, 0x40); + dma_mode = ata_get_best_mode(identify_info[88], ATA_MAX_UDMA, 0x40); } if (!dma_mode) { /* No UDMA mode found, try to find a multi-word DMA mode */ - dma_mode = get_best_mode(identify_info[63], ATA_MAX_MWDMA, 0x20); + dma_mode = ata_get_best_mode(identify_info[63], ATA_MAX_MWDMA, 0x20); features[1].id_word = 63; } else { features[1].id_word = 88; @@ -1263,14 +1262,14 @@ int STORAGE_INIT_ATTR ata_init(void) DEBUGF("ata: %d sectors per ata request\n",multisectors); - total_sectors = identify_info[60] | (identify_info[61] << 16); + total_sectors = (identify_info[61] << 16) | identify_info[60]; #ifdef HAVE_LBA48 - if (identify_info[83] & 0x0400 /* 48 bit address support */ - && total_sectors == 0x0FFFFFFF) /* and disk size >= 128 GiB */ - { /* (needs BigLBA addressing) */ - total_sectors = identify_info[100] | (identify_info[101] << 16) | ((uint64_t)identify_info[102] << 32) | ((uint64_t)identify_info[103] << 48); - + if (identify_info[83] & 0x0400 && total_sectors == 0x0FFFFFFF) { + total_sectors = ((uint64_t)identify_info[103] << 48) | + ((uint64_t)identify_info[102] << 32) | + ((uint64_t)identify_info[101] << 16) | + identify_info[100]; lba48 = true; /* use BigLBA */ } #endif /* HAVE_LBA48 */ diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h index 50aa5d8e8c..58c91b29c6 100644 --- a/firmware/export/config/ipod6g.h +++ b/firmware/export/config/ipod6g.h @@ -12,7 +12,7 @@ /* define this if you use an ATA controller */ #define CONFIG_STORAGE STORAGE_ATA -#define HAVE_ATA_DMA +#define HAVE_ATA_DMA #define ATA_MAX_UDMA 4 #define ATA_MAX_MWDMA 2 @@ -139,7 +139,7 @@ /* 6g has a standard battery of 550mAh, except for the thick 6g (2007 160gb) * which has a standard battery of 850mAh. - * + * * It's possible to buy 3rd party batteries up to 3000mAh. */ #define BATTERY_CAPACITY_DEFAULT 550 /* default battery capacity */ @@ -189,17 +189,12 @@ /* Define this if you can read an absolute wheel position */ #define HAVE_WHEEL_POSITION -#define SECTOR_SIZE 4096 - #define HAVE_ATA_SMART +#define SECTOR_SIZE 512 /* define this if the device has larger sectors when accessed via USB */ -/* (only relevant in disk.c, fat.c now always supports large virtual sectors) */ -//#define MAX_LOG_SECTOR_SIZE 4096 - -/* define this if the hard drive uses large physical sectors (ATA-7 feature) */ -/* and doesn't handle them in the drive firmware */ -//#define MAX_PHYS_SECTOR_SIZE 4096 +#define MAX_LOG_SECTOR_SIZE 4096 +//#define MAX_PHYS_SECTOR_SIZE 4096 // Only if we have various physical sector sizes #define HAVE_HARDWARE_CLICK diff --git a/firmware/export/config/vibe500.h b/firmware/export/config/vibe500.h index b6d2e5082a..48140e7a4a 100644 --- a/firmware/export/config/vibe500.h +++ b/firmware/export/config/vibe500.h @@ -170,14 +170,6 @@ /* Define this if you have adjustable CPU frequency */ #define HAVE_ADJUSTABLE_CPU_FREQ -/* define this if the device has larger sectors when accessed via USB */ -/* (only relevant in disk.c, fat.c now always supports large virtual sectors) */ -/* #define MAX_LOG_SECTOR_SIZE 2048 */ - -/* define this if the hard drive uses large physical sectors (ATA-7 feature) */ -/* and doesn't handle them in the drive firmware */ -/* #define MAX_PHYS_SECTOR_SIZE 1024 */ - #define MI4_FORMAT #define BOOTFILE_EXT "mi4" #define BOOTFILE "rockbox." BOOTFILE_EXT @@ -185,9 +177,6 @@ #define ICODE_ATTR_TREMOR_NOT_MDCT -/* DMA is used only for reading on PP502x because although reads are ~8x faster - * writes appear to be ~25% slower. - */ #ifndef BOOTLOADER #define HAVE_ATA_DMA #endif diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c index ee192ae3d1..97a55eba10 100644 --- a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c @@ -58,6 +58,18 @@ #define CEATA_DAT_NONBUSY_TIMEOUT 5000000 #define CEATA_MMC_RCA 1 +#if SECTOR_SIZE == 4096 +#define SIZE_SHIFT 3 /* ie 4096 >> 3 == 512 */ +#elif SECTOR_SIZE == 512 +#define SIZE_SHIFT 0 +#else +#error "Need to define SIZE_SHIFT for SECTOR_SIZE" +#endif + +#ifdef MAX_PHYS_SECTOR_SIZE +#error "Driver does not work with MAX_PHYS_SECTOR_SIZE" +#endif + /** static, private data **/ static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR; static uint16_t ata_identify_data[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR; @@ -69,18 +81,21 @@ static struct mutex ata_mutex; static struct semaphore ata_wakeup; static uint32_t ata_dma_flags; static long ata_last_activity_value = -1; -static long ata_sleep_timeout = 20 * HZ; +static long ata_sleep_timeout = 7 * HZ; static bool ata_powered; -static const int ata_retries = ATA_RETRIES; -static const bool ata_error_srst = true; static struct semaphore mmc_wakeup; static struct semaphore mmc_comp_wakeup; static int spinup_time = 0; static int dma_mode = 0; + +#if SECTOR_SIZE > 512 static char aligned_buffer[SECTOR_SIZE] STORAGE_ALIGN_ATTR; +#endif -static int ata_reset(void); +static const int ata_retries = ATA_RETRIES; +static const bool ata_error_srst = true; +static int ata_reset(void); static uint16_t ata_read_cbr(uint32_t volatile* reg) { @@ -102,8 +117,10 @@ static int ata_wait_for_not_bsy(long timeout) while (true) { uint8_t csd = ata_read_cbr(&ATA_PIO_CSD); - if (!(csd & BIT(7))) return 0; - if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(0); + if (!(csd & BIT(7))) + return 0; + if (TIMEOUT_EXPIRED(startusec, timeout)) + RET_ERR(0); yield(); } } @@ -115,8 +132,10 @@ static int ata_wait_for_rdy(long timeout) while (true) { uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); - if (dad & BIT(6)) return 0; - if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(1); + if (dad & BIT(6)) + return 0; + if (TIMEOUT_EXPIRED(startusec, timeout)) + RET_ERR(1); yield(); } } @@ -128,9 +147,12 @@ static int ata_wait_for_start_of_transfer(long timeout) while (true) { uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); - if (dad & BIT(0)) RET_ERR(1); - if ((dad & (BIT(7) | BIT(3))) == BIT(3)) return 0; - if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(2); + if (dad & BIT(0)) + RET_ERR(1); + if ((dad & (BIT(7) | BIT(3))) == BIT(3)) + return 0; + if (TIMEOUT_EXPIRED(startusec, timeout)) + RET_ERR(2); yield(); } } @@ -139,8 +161,10 @@ static int ata_wait_for_end_of_transfer(long timeout) { PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0); uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); - if (dad & BIT(0)) RET_ERR(1); - if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) return 0; + if (dad & BIT(0)) + RET_ERR(1); + if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) + return 0; RET_ERR(2); } @@ -148,13 +172,17 @@ static int mmc_dsta_check_command_success(bool disable_crc) { int rc = 0; uint32_t dsta = SDCI_DSTA; - if (dsta & SDCI_DSTA_RESTOUTE) rc |= 1; - if (dsta & SDCI_DSTA_RESENDE) rc |= 2; - if (dsta & SDCI_DSTA_RESINDE) rc |= 4; + if (dsta & SDCI_DSTA_RESTOUTE) + rc |= 1; + if (dsta & SDCI_DSTA_RESENDE) + rc |= 2; + if (dsta & SDCI_DSTA_RESINDE) + rc |= 4; if (!disable_crc) if (dsta & SDCI_DSTA_RESCRCE) rc |= 8; - if (rc) RET_ERR(rc); + if (rc) + RET_ERR(rc); return 0; } @@ -163,7 +191,8 @@ static bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int t long starttime = USEC_TIMER; while ((SDCI_STATE & SDCI_STATE_CMD_STATE_MASK) != SDCI_STATE_CMD_STATE_CMD_IDLE) { - if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(0); + if (TIMEOUT_EXPIRED(starttime, timeout)) + RET_ERR(0); yield(); } SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3 @@ -178,32 +207,38 @@ static bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int t | SDCI_STAC_CLR_RD_DATENDE6 | SDCI_STAC_CLR_RD_DATENDE7; SDCI_ARGU = arg; SDCI_CMD = cmd; - if (!(SDCI_DSTA & SDCI_DSTA_CMDRDY)) RET_ERR(1); + if (!(SDCI_DSTA & SDCI_DSTA_CMDRDY)) + RET_ERR(1); SDCI_CMD = cmd | SDCI_CMD_CMDSTR; long sleepbase = USEC_TIMER; - while (TIMEOUT_EXPIRED(sleepbase, 1000)) yield(); + while (TIMEOUT_EXPIRED(sleepbase, 1000)) + yield(); while (!(SDCI_DSTA & SDCI_DSTA_CMDEND)) { - if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(2); + if (TIMEOUT_EXPIRED(starttime, timeout)) + RET_ERR(2); yield(); } if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE) { while (!(SDCI_DSTA & SDCI_DSTA_RESEND)) { - if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(3); + if (TIMEOUT_EXPIRED(starttime, timeout)) + RET_ERR(3); yield(); } if (cmd & SDCI_CMD_RES_BUSY) while (SDCI_DSTA & SDCI_DSTA_DAT_BUSY) { - if (TIMEOUT_EXPIRED(starttime, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(4); + if (TIMEOUT_EXPIRED(starttime, CEATA_DAT_NONBUSY_TIMEOUT)) + RET_ERR(4); yield(); } } bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136; PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5); - if (result) *result = SDCI_RESP0; + if (result) + *result = SDCI_RESP0; return 0; } @@ -226,7 +261,8 @@ static int mmc_init(void) uint32_t result; do { - if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1); + if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) + RET_ERR(1); sleep(HZ / 100); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND) | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3 @@ -251,7 +287,8 @@ static int mmc_init(void) MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA), NULL, CEATA_COMMAND_TIMEOUT), 3, 5); PASS_RC(mmc_get_card_status(&result), 3, 6); - if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) RET_ERR(7); + if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) + RET_ERR(7); return 0; } @@ -285,7 +322,8 @@ static int ceata_soft_reset(void) do { PASS_RC(mmc_fastio_read(0xf, &status), 2, 2); - if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(3); + if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) + RET_ERR(3); sleep(HZ / 100); } while (status & 0x80); @@ -298,16 +336,21 @@ static int mmc_dsta_check_data_success(void) uint32_t dsta = SDCI_DSTA; if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE)) { - if (dsta & SDCI_DSTA_WR_DATCRCE) rc |= 1; - if (dsta & SDCI_DSTA_RD_DATCRCE) rc |= 2; - if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) rc |= 4; - else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) rc |= 8; + if (dsta & SDCI_DSTA_WR_DATCRCE) + rc |= 1; + if (dsta & SDCI_DSTA_RD_DATCRCE) + rc |= 2; + if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) + rc |= 4; + else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) + rc |= 8; } if (dsta & (SDCI_DSTA_RD_DATENDE0 | SDCI_DSTA_RD_DATENDE1 | SDCI_DSTA_RD_DATENDE2 | SDCI_DSTA_RD_DATENDE3 | SDCI_DSTA_RD_DATENDE4 | SDCI_DSTA_RD_DATENDE5 | SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7)) rc |= 16; - if (rc) RET_ERR(rc); + if (rc) + RET_ERR(rc); return 0; } @@ -320,7 +363,8 @@ static void mmc_discard_irq(void) static int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size) { - if (size > 0x10) RET_ERR(0); + if (size > 0x10) + RET_ERR(0); mmc_discard_irq(); SDCI_DMASIZE = size; SDCI_DMACOUNT = 1; @@ -334,8 +378,8 @@ static int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc) | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), NULL, CEATA_COMMAND_TIMEOUT), 2, 1); - if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) - == OBJ_WAIT_TIMEDOUT) RET_ERR(2); + if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) + RET_ERR(2); PASS_RC(mmc_dsta_check_data_success(), 2, 3); return 0; } @@ -343,7 +387,8 @@ static int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size static int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size) { uint32_t i; - if (size > 0x10) RET_ERR(0); + if (size > 0x10) + RET_ERR(0); mmc_discard_irq(); SDCI_DMASIZE = size; SDCI_DMACOUNT = 0; @@ -357,13 +402,15 @@ static int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t siz | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), NULL, CEATA_COMMAND_TIMEOUT), 3, 1); SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; - for (i = 0; i < size / 4; i++) SDCI_DATA = ((uint32_t*)dest)[i]; + for (i = 0; i < size / 4; i++) + SDCI_DATA = ((uint32_t*)dest)[i]; long startusec = USEC_TIMER; - if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) - == OBJ_WAIT_TIMEDOUT) RET_ERR(2); + if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) + RET_ERR(2); while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE) { - if (TIMEOUT_EXPIRED(startusec, CEATA_COMMAND_TIMEOUT)) RET_ERR(3); + if (TIMEOUT_EXPIRED(startusec, CEATA_COMMAND_TIMEOUT)) + RET_ERR(3); yield(); } PASS_RC(mmc_dsta_check_data_success(), 3, 4); @@ -380,13 +427,17 @@ static int ceata_init(int buswidth) | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING) | MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED), &result, CEATA_COMMAND_TIMEOUT), 3, 0); - if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(1); + if (result & MMC_STATUS_SWITCH_ERROR) + RET_ERR(1); if (buswidth > 1) { int setting; - if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT; - else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT; - else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT; + if (buswidth == 4) + setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT; + else if (buswidth == 8) + setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT; + else + setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT; PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, @@ -394,7 +445,8 @@ static int ceata_init(int buswidth) | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH) | MMC_CMD_SWITCH_VALUE(setting), &result, CEATA_COMMAND_TIMEOUT), 3, 2); - if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(3); + if (result & MMC_STATUS_SWITCH_ERROR) + RET_ERR(3); if (buswidth == 4) SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT; else if (buswidth == 8) @@ -402,7 +454,8 @@ static int ceata_init(int buswidth) } PASS_RC(ceata_soft_reset(), 3, 4); PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5); - if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) RET_ERR(6); + if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) + RET_ERR(6); PASS_RC(mmc_fastio_write(6, 0), 3, 7); return 0; } @@ -426,8 +479,10 @@ static int ceata_wait_idle(void) { uint32_t status; PASS_RC(mmc_fastio_read(0xf, &status), 1, 0); - if (!(status & 0x88)) return 0; - if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(1); + if (!(status & 0x88)) + return 0; + if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) + RET_ERR(1); sleep(HZ / 20); } } @@ -476,7 +531,8 @@ static int ceata_rw_multiple_block(bool write, void* buf, uint32_t count, long t | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count), NULL, CEATA_COMMAND_TIMEOUT), 3, 0); - if (write) SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; + if (write) + SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; if (semaphore_wait(&mmc_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) { PASS_RC(ceata_cancel_command(), 3, 1); @@ -509,7 +565,8 @@ static int ata_identify(uint16_t* buf) ata_write_cbr(&ATA_PIO_DVR, 0); ata_write_cbr(&ATA_PIO_CSD, CMD_IDENTIFY); PASS_RC(ata_wait_for_start_of_transfer(10000000), 1, 1); - for (i = 0; i < ATA_IDENTIFY_WORDS; i++) buf[i] = ata_read_cbr(&ATA_PIO_DTR); + for (i = 0; i < ATA_IDENTIFY_WORDS; i++) + buf[i] = ata_read_cbr(&ATA_PIO_DTR); } return 0; } @@ -548,6 +605,34 @@ static int ata_set_feature(uint32_t feature, uint32_t param) return 0; } +#ifdef HAVE_ATA_DMA +static int udmatimes[ATA_MAX_UDMA + 1] = { + 0x4071152, + 0x2050d52, + 0x2030a52, + 0x1020a52, + 0x1010a52 +}; +static int mwdmatimes[ATA_MAX_MWDMA + 1] = { + 0x1c175, + 0x7083, + 0x5072 +}; +static int ata_get_best_mode(unsigned short identword, int max, int modetype) +{ + unsigned short testbit = BIT_N(max); + + while (1) { + if (identword & testbit) + return max | modetype; + testbit >>= 1; + if (!testbit) + return 0; + max--; + } +} +#endif + /* * ATA_UDMA_TIME register is documented on s3c6400 datasheet, information * included in s5l8700 datasheet is wrong or not valid for s5l8702. @@ -572,10 +657,10 @@ static int ata_power_up(void) ata_set_active(); ide_power_enable(true); long spinup_start = current_tick; - if (ceata) - { + if (ceata) { ata_lba48 = true; ata_dma = true; + dma_mode = 0xff; /* Canary */ PCON(8) = 0x33333333; PCON(9) = 0x00000033; PCON(11) |= 0xf; @@ -596,10 +681,7 @@ static int ata_power_up(void) sleep(HZ / 100); PASS_RC(ceata_init(8), 3, 1); PASS_RC(ata_identify(ata_identify_data), 3, 2); - dma_mode = 0x44; - } - else - { + } else { PCON(7) = 0x44444444; PCON(8) = 0x44444444; PCON(9) = 0x44444444; @@ -619,64 +701,35 @@ static int ata_power_up(void) ATA_PIO_LHR = 0; ATA_CFG = BIT(6); while (!(ATA_PIO_READY & BIT(1))) yield(); + PASS_RC(ata_identify(ata_identify_data), 3, 3); - uint32_t piotime = 0x11f3; - uint32_t mdmatime = 0x1c175; - uint32_t udmatime = 0x4071152; - uint32_t param = 0; - ata_dma_flags = 0; - ata_lba48 = ata_identify_data[83] & BIT(10) ? true : false; - if (ata_identify_data[53] & BIT(1)) - { - if (ata_identify_data[64] & BIT(1)) piotime = 0x2072; - else if (ata_identify_data[64] & BIT(0)) piotime = 0x7083; - } - if (ata_identify_data[63] & BIT(2)) + + uint32_t piotime = 0x11f3; /* PIO0-2? */ + if (ata_identify_data[53] & BIT(1)) /* Word 64..70 valid */ { - mdmatime = 0x5072; - param = 0x22; + if (ata_identify_data[64] & BIT(1)) + piotime = 0x2072; /* PIO mode 4 */ + else if (ata_identify_data[64] & BIT(0)) + piotime = 0x7083; /* PIO mode 3 */ } - else if (ata_identify_data[63] & BIT(1)) + ATA_PIO_TIME = piotime; + + uint32_t param = 0; + ata_dma_flags = 0; +#ifdef HAVE_ATA_DMA + if ((ata_identify_data[53] & BIT(2)) && (ata_identify_data[88] & BITRANGE(0, 4))) /* Any UDMA */ { - mdmatime = 0x7083; - param = 0x21; + param = ata_get_best_mode(ata_identify_data[88], ATA_MAX_UDMA, 0x40); + ATA_UDMA_TIME = udmatimes[param & 0xf]; + ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10); } - if (ata_identify_data[63] & BITRANGE(0, 2)) + if (!param && ata_identify_data[63] & BITRANGE(0, 2)) /* Fall back to any MWDMA */ { + param = ata_get_best_mode(ata_identify_data[63], ATA_MAX_MWDMA, 0x20); + ATA_MDMA_TIME = mwdmatimes[param & 0xf]; ata_dma_flags = BIT(3) | BIT(10); - param |= 0x20; - } - if (ata_identify_data[53] & BIT(2)) - { - if (ata_identify_data[88] & BIT(4)) - { - udmatime = 0x1010a52; - param = 0x44; - } - else if (ata_identify_data[88] & BIT(3)) - { - udmatime = 0x1020a52; - param = 0x43; - } - else if (ata_identify_data[88] & BIT(2)) - { - udmatime = 0x2030a52; - param = 0x42; - } - else if (ata_identify_data[88] & BIT(1)) - { - udmatime = 0x2050d52; - param = 0x41; - } - else if (ata_identify_data[88] & BIT(0)) - { - param = 0x40; - } - if (ata_identify_data[88] & BITRANGE(0, 4)) - { - ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10); - } } +#endif /* HAVE_ATA_DMA */ ata_dma = param ? true : false; dma_mode = param; PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ @@ -688,19 +741,22 @@ static int ata_power_up(void) PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */ if (ata_identify_data[83] & BIT(9)) PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ - ATA_PIO_TIME = piotime; - ATA_MDMA_TIME = mdmatime; - ATA_UDMA_TIME = udmatime; } spinup_time = current_tick - spinup_start; - if (ata_lba48) - ata_total_sectors = ata_identify_data[100] - | (((uint64_t)ata_identify_data[101]) << 16) - | (((uint64_t)ata_identify_data[102]) << 32) - | (((uint64_t)ata_identify_data[103]) << 48); - else - ata_total_sectors = ata_identify_data[60] | (((uint32_t)ata_identify_data[61]) << 16); - ata_total_sectors >>= 3; /* ie SECTOR_SIZE/512. */ + + ata_total_sectors = (ata_identify_data[61] << 16) | ata_identify_data[60]; + if ( ata_identify_data[83] & BIT(10) && ata_total_sectors == 0x0FFFFFFF) + { + ata_total_sectors = ((uint64_t)ata_identify_data[103] << 48) | + ((uint64_t)ata_identify_data[102] << 32) | + ((uint64_t)ata_identify_data[101] << 16) | + ata_identify_data[100]; + ata_lba48 = true; + } else { + ata_lba48 = false; + } + + ata_total_sectors >>= SIZE_SHIFT; ata_powered = true; ata_set_active(); return 0; @@ -708,7 +764,8 @@ static int ata_power_up(void) static void ata_power_down(void) { - if (!ata_powered) return; + if (!ata_powered) + return; if (ceata) { memset(ceata_taskfile, 0, 16); @@ -727,7 +784,8 @@ static void ata_power_down(void) ata_wait_for_rdy(1000000); sleep(HZ / 30); ATA_CONTROL = 0; - while (!(ATA_CONTROL & BIT(1))) yield(); + while (!(ATA_CONTROL & BIT(1))) + yield(); PWRCON(0) |= (1 << 5); } PCON(7) = 0; @@ -744,18 +802,18 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo if (ceata) { memset(ceata_taskfile, 0, 16); - ceata_taskfile[0x2] = cnt >> 5; - ceata_taskfile[0x3] = sector >> 21; - ceata_taskfile[0x4] = sector >> 29; - ceata_taskfile[0x5] = sector >> 37; - ceata_taskfile[0xa] = cnt << 3; - ceata_taskfile[0xb] = sector << 3; - ceata_taskfile[0xc] = sector >> 5; - ceata_taskfile[0xd] = sector >> 13; + ceata_taskfile[0x2] = cnt >> (8-SIZE_SHIFT); + ceata_taskfile[0x3] = sector >> (24-SIZE_SHIFT); + ceata_taskfile[0x4] = sector >> (32-SIZE_SHIFT); + ceata_taskfile[0x5] = sector >> (40-SIZE_SHIFT); + ceata_taskfile[0xa] = cnt << SIZE_SHIFT; + ceata_taskfile[0xb] = sector << SIZE_SHIFT; + ceata_taskfile[0xc] = sector >> (8-SIZE_SHIFT); + ceata_taskfile[0xd] = sector >> (16-SIZE_SHIFT); ceata_taskfile[0xf] = write ? CMD_WRITE_DMA_EXT : CMD_READ_DMA_EXT; PASS_RC(ceata_wait_idle(), 2, 0); PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1); - PASS_RC(ceata_rw_multiple_block(write, buffer, cnt << 3, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2); + PASS_RC(ceata_rw_multiple_block(write, buffer, cnt << SIZE_SHIFT, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2); } else { @@ -763,14 +821,14 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo ata_write_cbr(&ATA_PIO_DVR, 0); if (ata_lba48) { - ata_write_cbr(&ATA_PIO_SCR, cnt >> 5); - ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff); - ata_write_cbr(&ATA_PIO_LHR, (sector >> 37) & 0xff); - ata_write_cbr(&ATA_PIO_LMR, (sector >> 29) & 0xff); - ata_write_cbr(&ATA_PIO_LLR, (sector >> 21) & 0xff); - ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff); - ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff); - ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff); + ata_write_cbr(&ATA_PIO_SCR, (cnt >> (8-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_SCR, (cnt << SIZE_SHIFT) & 0xff); + ata_write_cbr(&ATA_PIO_LHR, (sector >> (40-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LMR, (sector >> (32-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LLR, (sector >> (24-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LHR, (sector >> (16-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LMR, (sector >> (8-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LLR, (sector << SIZE_SHIFT) & 0xff); ata_write_cbr(&ATA_PIO_DVR, BIT(6)); if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_WRITE_DMA_EXT : CMD_WRITE_MULTIPLE_EXT); @@ -779,16 +837,17 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo } else { - ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff); - ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff); - ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff); - ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff); - ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 21) & 0xf)); + ata_write_cbr(&ATA_PIO_SCR, (cnt << SIZE_SHIFT) & 0xff); + ata_write_cbr(&ATA_PIO_LHR, (sector >> (16-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LMR, (sector >> (8-SIZE_SHIFT)) & 0xff); + ata_write_cbr(&ATA_PIO_LLR, (sector << SIZE_SHIFT) & 0xff); + ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> (24-SIZE_SHIFT)) & 0xf)); if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_WRITE_DMA : CMD_WRITE_SECTORS); else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_READ_DMA : CMD_READ_MULTIPLE); } +#ifdef HAVE_ATA_DMA if (ata_dma) { PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1); @@ -811,8 +870,7 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo ATA_IRQ = BITRANGE(0, 4); ATA_IRQ_MASK = BIT(0); ATA_COMMAND = BIT(0); - if (semaphore_wait(&ata_wakeup, 500000 * HZ / 1000000) - == OBJ_WAIT_TIMEDOUT) + if (semaphore_wait(&ata_wakeup, 500000 * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) { ATA_COMMAND = BIT(1); ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); @@ -822,8 +880,9 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); } else +#endif // HAVE_ATA_DMA { - cnt *= SECTOR_SIZE / 512; + cnt <<= SIZE_SHIFT; while (cnt--) { int i; @@ -834,7 +893,7 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo else for (i = 0; i < 256; i++) ((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR); - buffer += 512; + buffer += (SECTOR_SIZE >> SIZE_SHIFT); } } PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 3); @@ -852,6 +911,7 @@ static int ata_rw_chunk(uint64_t sector, uint32_t cnt, void* buffer, bool write) static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write) { +#if SECTOR_SIZE > 512 if (STORAGE_OVERLAP((uint32_t)buffer)) { while (count) @@ -871,19 +931,27 @@ static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool wr return 0; } +#endif - if (!ata_powered) ata_power_up(); - if (sector + count > ata_total_sectors) RET_ERR(0); + if (!ata_powered) + ata_power_up(); + if (sector + count > ata_total_sectors) + RET_ERR(0); ata_set_active(); - if (ata_dma && write) commit_dcache(); - else if (ata_dma) commit_discard_dcache(); - if (!ceata) ATA_COMMAND = BIT(1); + if (ata_dma && write) + commit_dcache(); + else if (ata_dma) + commit_discard_dcache(); + if (!ceata) + ATA_COMMAND = BIT(1); + while (count) { - uint32_t cnt = MIN(ata_lba48 ? 8192 : 32, count); + uint32_t cnt = MIN(ata_lba48 ? (65536 >> SIZE_SHIFT) : (256 >> SIZE_SHIFT), count); int rc = -1; rc = ata_rw_chunk(sector, cnt, buffer, write); - if (rc && ata_error_srst) ata_reset(); + if (rc && ata_error_srst) + ata_reset(); if (rc && ata_retries) { void* buf = buffer; @@ -895,9 +963,11 @@ static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool wr while (tries-- && rc) { rc = ata_rw_chunk(sect, 1, buf, write); - if (rc && ata_error_srst) ata_reset(); + if (rc && ata_error_srst) + ata_reset(); } - if (rc) break; + if (rc) + break; buf += SECTOR_SIZE; } } @@ -915,9 +985,13 @@ int ata_soft_reset(void) { int rc; mutex_lock(&ata_mutex); - if (!ata_powered) PASS_RC(ata_power_up(), 1, 0); + if (!ata_powered) + PASS_RC(ata_power_up(), 1, 0); ata_set_active(); - if (ceata) rc = ceata_soft_reset(); + if (ceata) + { + rc = ceata_soft_reset(); + } else { ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2)); @@ -944,7 +1018,8 @@ static int ata_reset(void) { int rc; mutex_lock(&ata_mutex); - if (!ata_powered) PASS_RC(ata_power_up(), 2, 0); + if (!ata_powered) + PASS_RC(ata_power_up(), 2, 0); ata_set_active(); rc = ata_soft_reset(); if (IS_ERR(rc)) @@ -956,7 +1031,8 @@ static int ata_reset(void) ata_power_down(); sleep(HZ * 3); int rc2 = ata_power_up(); - if (IS_ERR(rc2)) rc = ERR_RC((rc << 2) | 2); + if (IS_ERR(rc2)) + rc = ERR_RC((rc << 2) | 2); } else rc = 1; } @@ -1036,14 +1112,21 @@ void ata_spin(void) ata_set_active(); } +#ifdef STORAGE_GET_INFO void ata_get_info(IF_MD(int drive,) struct storage_info *info) { - (*info).sector_size = SECTOR_SIZE; + /* Logical sector size */ + if ((ata_identify_data[106] & 0xd000) == 0x5000) + info->sector_size = ata_identify_data[117] | (ata_identify_data[118] << 16); + else + info->sector_size = SECTOR_SIZE; + (*info).num_sectors = ata_total_sectors; (*info).vendor = "Apple"; (*info).product = "iPod Classic"; (*info).revision = "1.0"; } +#endif long ata_last_disk_activity(void) { @@ -1064,7 +1147,8 @@ int ata_init(void) mutex_lock(&ata_mutex); int rc = ata_power_up(); mutex_unlock(&ata_mutex); - if (IS_ERR(rc)) return rc; + if (IS_ERR(rc)) + return rc; return 0; } @@ -1101,7 +1185,8 @@ static int ata_smart(uint16_t* buf) ata_write_cbr(&ATA_PIO_DVR, BIT(6)); ata_write_cbr(&ATA_PIO_CSD, CMD_SMART); PASS_RC(ata_wait_for_start_of_transfer(10000000), 3, 7); - for (i = 0; i < 0x100; i++) buf[i] = ata_read_cbr(&ATA_PIO_DTR); + for (i = 0; i < 0x100; i++) + buf[i] = ata_read_cbr(&ATA_PIO_DTR); } ata_set_active(); return 0; @@ -1136,24 +1221,29 @@ int ata_spinup_time(void) return spinup_time; } +#ifdef HAVE_ATA_DMA int ata_get_dma_mode(void) { return dma_mode; } +#endif void INT_ATA(void) { uint32_t ata_irq = ATA_IRQ; ATA_IRQ = ata_irq; - if (ata_irq & ATA_IRQ_MASK) semaphore_release(&ata_wakeup); + if (ata_irq & ATA_IRQ_MASK) + semaphore_release(&ata_wakeup); ATA_IRQ_MASK = 0; } void INT_MMC(void) { uint32_t irq = SDCI_IRQ; - if (irq & SDCI_IRQ_DAT_DONE_INT) semaphore_release(&mmc_wakeup); - if (irq & SDCI_IRQ_IOCARD_IRQ_INT) semaphore_release(&mmc_comp_wakeup); + if (irq & SDCI_IRQ_DAT_DONE_INT) + semaphore_release(&mmc_wakeup); + if (irq & SDCI_IRQ_IOCARD_IRQ_INT) + semaphore_release(&mmc_comp_wakeup); SDCI_IRQ = irq; } |