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
This commit is contained in:
Solomon Peachy 2024-10-14 18:09:17 -04:00
parent 9efed5542e
commit 563da70139
5 changed files with 277 additions and 199 deletions

View file

@ -1430,11 +1430,13 @@ static int disk_callback(int btn, struct gui_synclist *lists)
simplelist_addline( simplelist_addline(
"Firmware: %s", buf); "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 #ifdef HAVE_LBA48
if (identify_info[83] & 0x0400 if (identify_info[83] & 0x0400 && total_sectors == 0x0FFFFFFF)
&& total_sectors == 0x0FFFFFFF) total_sectors = ((uint64_t)identify_info[103] << 48) |
total_sectors = identify_info[100] | ((uint64_t)identify_info[101] << 16) | ((uint64_t)identify_info[102] << 32) | ((uint64_t)identify_info[103] << 48); ((uint64_t)identify_info[102] << 32) |
((uint64_t)identify_info[101] << 16) |
identify_info[100];
#endif #endif
uint32_t sector_size; uint32_t sector_size;
@ -1555,6 +1557,9 @@ static int disk_callback(int btn, struct gui_synclist *lists)
if (i == 0) { if (i == 0) {
simplelist_addline( simplelist_addline(
"DMA not enabled"); "DMA not enabled");
} else if (i == 0xff) {
simplelist_addline(
"CE-ATA mode");
} else { } else {
simplelist_addline( simplelist_addline(
"DMA mode: %s %c", "DMA mode: %s %c",

View file

@ -114,7 +114,6 @@ static int multisectors; /* number of supported multisectors */
static unsigned short identify_info[ATA_IDENTIFY_WORDS]; static unsigned short identify_info[ATA_IDENTIFY_WORDS];
#ifdef MAX_PHYS_SECTOR_SIZE #ifdef MAX_PHYS_SECTOR_SIZE
struct sector_cache_entry { struct sector_cache_entry {
bool inuse; bool inuse;
sector_t sectornum; /* logical sector */ sector_t sectornum; /* logical sector */
@ -1068,7 +1067,7 @@ static int set_multiple_mode(int sectors)
} }
#ifdef HAVE_ATA_DMA #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); unsigned short testbit = BIT_N(max);
@ -1118,12 +1117,12 @@ static int set_features(void)
#ifdef HAVE_ATA_DMA #ifdef HAVE_ATA_DMA
if (identify_info[53] & (1<<2)) { if (identify_info[53] & (1<<2)) {
/* Ultra DMA mode info present, find a mode */ /* 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) { if (!dma_mode) {
/* No UDMA mode found, try to find a multi-word 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; features[1].id_word = 63;
} else { } else {
features[1].id_word = 88; 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); 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 #ifdef HAVE_LBA48
if (identify_info[83] & 0x0400 /* 48 bit address support */ if (identify_info[83] & 0x0400 && total_sectors == 0x0FFFFFFF) {
&& total_sectors == 0x0FFFFFFF) /* and disk size >= 128 GiB */ total_sectors = ((uint64_t)identify_info[103] << 48) |
{ /* (needs BigLBA addressing) */ ((uint64_t)identify_info[102] << 32) |
total_sectors = identify_info[100] | (identify_info[101] << 16) | ((uint64_t)identify_info[102] << 32) | ((uint64_t)identify_info[103] << 48); ((uint64_t)identify_info[101] << 16) |
identify_info[100];
lba48 = true; /* use BigLBA */ lba48 = true; /* use BigLBA */
} }
#endif /* HAVE_LBA48 */ #endif /* HAVE_LBA48 */

View file

@ -12,7 +12,7 @@
/* define this if you use an ATA controller */ /* define this if you use an ATA controller */
#define CONFIG_STORAGE STORAGE_ATA #define CONFIG_STORAGE STORAGE_ATA
#define HAVE_ATA_DMA #define HAVE_ATA_DMA
#define ATA_MAX_UDMA 4 #define ATA_MAX_UDMA 4
#define ATA_MAX_MWDMA 2 #define ATA_MAX_MWDMA 2
@ -139,7 +139,7 @@
/* 6g has a standard battery of 550mAh, except for the thick 6g (2007 160gb) /* 6g has a standard battery of 550mAh, except for the thick 6g (2007 160gb)
* which has a standard battery of 850mAh. * which has a standard battery of 850mAh.
* *
* It's possible to buy 3rd party batteries up to 3000mAh. * It's possible to buy 3rd party batteries up to 3000mAh.
*/ */
#define BATTERY_CAPACITY_DEFAULT 550 /* default battery capacity */ #define BATTERY_CAPACITY_DEFAULT 550 /* default battery capacity */
@ -189,17 +189,12 @@
/* Define this if you can read an absolute wheel position */ /* Define this if you can read an absolute wheel position */
#define HAVE_WHEEL_POSITION #define HAVE_WHEEL_POSITION
#define SECTOR_SIZE 4096
#define HAVE_ATA_SMART #define HAVE_ATA_SMART
#define SECTOR_SIZE 512
/* define this if the device has larger sectors when accessed via USB */ /* 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 MAX_LOG_SECTOR_SIZE 4096 //#define MAX_PHYS_SECTOR_SIZE 4096 // Only if we have various physical sector sizes
/* 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 HAVE_HARDWARE_CLICK #define HAVE_HARDWARE_CLICK

View file

@ -170,14 +170,6 @@
/* Define this if you have adjustable CPU frequency */ /* Define this if you have adjustable CPU frequency */
#define HAVE_ADJUSTABLE_CPU_FREQ #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 MI4_FORMAT
#define BOOTFILE_EXT "mi4" #define BOOTFILE_EXT "mi4"
#define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTFILE "rockbox." BOOTFILE_EXT
@ -185,9 +177,6 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT #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 #ifndef BOOTLOADER
#define HAVE_ATA_DMA #define HAVE_ATA_DMA
#endif #endif

View file

@ -58,6 +58,18 @@
#define CEATA_DAT_NONBUSY_TIMEOUT 5000000 #define CEATA_DAT_NONBUSY_TIMEOUT 5000000
#define CEATA_MMC_RCA 1 #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, private data **/
static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR; static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR;
static uint16_t ata_identify_data[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR; static uint16_t ata_identify_data[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR;
@ -69,19 +81,22 @@ static struct mutex ata_mutex;
static struct semaphore ata_wakeup; static struct semaphore ata_wakeup;
static uint32_t ata_dma_flags; static uint32_t ata_dma_flags;
static long ata_last_activity_value = -1; 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 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_wakeup;
static struct semaphore mmc_comp_wakeup; static struct semaphore mmc_comp_wakeup;
static int spinup_time = 0; static int spinup_time = 0;
static int dma_mode = 0; static int dma_mode = 0;
#if SECTOR_SIZE > 512
static char aligned_buffer[SECTOR_SIZE] STORAGE_ALIGN_ATTR; static char aligned_buffer[SECTOR_SIZE] STORAGE_ALIGN_ATTR;
#endif
static const int ata_retries = ATA_RETRIES;
static const bool ata_error_srst = true;
static int ata_reset(void); static int ata_reset(void);
static uint16_t ata_read_cbr(uint32_t volatile* reg) static uint16_t ata_read_cbr(uint32_t volatile* reg)
{ {
while (!(ATA_PIO_READY & 2)); while (!(ATA_PIO_READY & 2));
@ -102,8 +117,10 @@ static int ata_wait_for_not_bsy(long timeout)
while (true) while (true)
{ {
uint8_t csd = ata_read_cbr(&ATA_PIO_CSD); uint8_t csd = ata_read_cbr(&ATA_PIO_CSD);
if (!(csd & BIT(7))) return 0; if (!(csd & BIT(7)))
if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(0); return 0;
if (TIMEOUT_EXPIRED(startusec, timeout))
RET_ERR(0);
yield(); yield();
} }
} }
@ -115,8 +132,10 @@ static int ata_wait_for_rdy(long timeout)
while (true) while (true)
{ {
uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
if (dad & BIT(6)) return 0; if (dad & BIT(6))
if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(1); return 0;
if (TIMEOUT_EXPIRED(startusec, timeout))
RET_ERR(1);
yield(); yield();
} }
} }
@ -128,9 +147,12 @@ static int ata_wait_for_start_of_transfer(long timeout)
while (true) while (true)
{ {
uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
if (dad & BIT(0)) RET_ERR(1); if (dad & BIT(0))
if ((dad & (BIT(7) | BIT(3))) == BIT(3)) return 0; RET_ERR(1);
if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(2); if ((dad & (BIT(7) | BIT(3))) == BIT(3))
return 0;
if (TIMEOUT_EXPIRED(startusec, timeout))
RET_ERR(2);
yield(); 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); PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
if (dad & BIT(0)) RET_ERR(1); if (dad & BIT(0))
if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) return 0; RET_ERR(1);
if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6))
return 0;
RET_ERR(2); RET_ERR(2);
} }
@ -148,13 +172,17 @@ static int mmc_dsta_check_command_success(bool disable_crc)
{ {
int rc = 0; int rc = 0;
uint32_t dsta = SDCI_DSTA; uint32_t dsta = SDCI_DSTA;
if (dsta & SDCI_DSTA_RESTOUTE) rc |= 1; if (dsta & SDCI_DSTA_RESTOUTE)
if (dsta & SDCI_DSTA_RESENDE) rc |= 2; rc |= 1;
if (dsta & SDCI_DSTA_RESINDE) rc |= 4; if (dsta & SDCI_DSTA_RESENDE)
rc |= 2;
if (dsta & SDCI_DSTA_RESINDE)
rc |= 4;
if (!disable_crc) if (!disable_crc)
if (dsta & SDCI_DSTA_RESCRCE) if (dsta & SDCI_DSTA_RESCRCE)
rc |= 8; rc |= 8;
if (rc) RET_ERR(rc); if (rc)
RET_ERR(rc);
return 0; 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; long starttime = USEC_TIMER;
while ((SDCI_STATE & SDCI_STATE_CMD_STATE_MASK) != SDCI_STATE_CMD_STATE_CMD_IDLE) 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(); yield();
} }
SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3 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_STAC_CLR_RD_DATENDE6 | SDCI_STAC_CLR_RD_DATENDE7;
SDCI_ARGU = arg; SDCI_ARGU = arg;
SDCI_CMD = cmd; 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; SDCI_CMD = cmd | SDCI_CMD_CMDSTR;
long sleepbase = USEC_TIMER; long sleepbase = USEC_TIMER;
while (TIMEOUT_EXPIRED(sleepbase, 1000)) yield(); while (TIMEOUT_EXPIRED(sleepbase, 1000))
yield();
while (!(SDCI_DSTA & SDCI_DSTA_CMDEND)) while (!(SDCI_DSTA & SDCI_DSTA_CMDEND))
{ {
if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(2); if (TIMEOUT_EXPIRED(starttime, timeout))
RET_ERR(2);
yield(); yield();
} }
if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE) if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE)
{ {
while (!(SDCI_DSTA & SDCI_DSTA_RESEND)) while (!(SDCI_DSTA & SDCI_DSTA_RESEND))
{ {
if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(3); if (TIMEOUT_EXPIRED(starttime, timeout))
RET_ERR(3);
yield(); yield();
} }
if (cmd & SDCI_CMD_RES_BUSY) if (cmd & SDCI_CMD_RES_BUSY)
while (SDCI_DSTA & SDCI_DSTA_DAT_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(); yield();
} }
} }
bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136; bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136;
PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5); PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5);
if (result) *result = SDCI_RESP0; if (result)
*result = SDCI_RESP0;
return 0; return 0;
} }
@ -226,7 +261,8 @@ static int mmc_init(void)
uint32_t result; uint32_t result;
do do
{ {
if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1); if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT))
RET_ERR(1);
sleep(HZ / 100); sleep(HZ / 100);
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND) PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND)
| SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3 | 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), MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA),
NULL, CEATA_COMMAND_TIMEOUT), 3, 5); NULL, CEATA_COMMAND_TIMEOUT), 3, 5);
PASS_RC(mmc_get_card_status(&result), 3, 6); 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; return 0;
} }
@ -285,7 +322,8 @@ static int ceata_soft_reset(void)
do do
{ {
PASS_RC(mmc_fastio_read(0xf, &status), 2, 2); 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); sleep(HZ / 100);
} }
while (status & 0x80); while (status & 0x80);
@ -298,16 +336,21 @@ static int mmc_dsta_check_data_success(void)
uint32_t dsta = SDCI_DSTA; uint32_t dsta = SDCI_DSTA;
if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE)) if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE))
{ {
if (dsta & SDCI_DSTA_WR_DATCRCE) rc |= 1; if (dsta & SDCI_DSTA_WR_DATCRCE)
if (dsta & SDCI_DSTA_RD_DATCRCE) rc |= 2; rc |= 1;
if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) rc |= 4; if (dsta & SDCI_DSTA_RD_DATCRCE)
else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) rc |= 8; 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 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_DATENDE3 | SDCI_DSTA_RD_DATENDE4 | SDCI_DSTA_RD_DATENDE5
| SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7)) | SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7))
rc |= 16; rc |= 16;
if (rc) RET_ERR(rc); if (rc)
RET_ERR(rc);
return 0; 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) 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(); mmc_discard_irq();
SDCI_DMASIZE = size; SDCI_DMASIZE = size;
SDCI_DMACOUNT = 1; 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_ADDRESS(addr & 0xfc)
| MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
NULL, CEATA_COMMAND_TIMEOUT), 2, 1); NULL, CEATA_COMMAND_TIMEOUT), 2, 1);
if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT)
== OBJ_WAIT_TIMEDOUT) RET_ERR(2); RET_ERR(2);
PASS_RC(mmc_dsta_check_data_success(), 2, 3); PASS_RC(mmc_dsta_check_data_success(), 2, 3);
return 0; 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) static int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size)
{ {
uint32_t i; uint32_t i;
if (size > 0x10) RET_ERR(0); if (size > 0x10)
RET_ERR(0);
mmc_discard_irq(); mmc_discard_irq();
SDCI_DMASIZE = size; SDCI_DMASIZE = size;
SDCI_DMACOUNT = 0; 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), | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
NULL, CEATA_COMMAND_TIMEOUT), 3, 1); NULL, CEATA_COMMAND_TIMEOUT), 3, 1);
SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; 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; long startusec = USEC_TIMER;
if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT)
== OBJ_WAIT_TIMEDOUT) RET_ERR(2); RET_ERR(2);
while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE) 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(); yield();
} }
PASS_RC(mmc_dsta_check_data_success(), 3, 4); 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_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING)
| MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED), | MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED),
&result, CEATA_COMMAND_TIMEOUT), 3, 0); &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) if (buswidth > 1)
{ {
int setting; int setting;
if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT; if (buswidth == 4)
else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT; setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT;
else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT; 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 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_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | 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_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH)
| MMC_CMD_SWITCH_VALUE(setting), | MMC_CMD_SWITCH_VALUE(setting),
&result, CEATA_COMMAND_TIMEOUT), 3, 2); &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) if (buswidth == 4)
SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT; SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT;
else if (buswidth == 8) else if (buswidth == 8)
@ -402,7 +454,8 @@ static int ceata_init(int buswidth)
} }
PASS_RC(ceata_soft_reset(), 3, 4); PASS_RC(ceata_soft_reset(), 3, 4);
PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5); 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); PASS_RC(mmc_fastio_write(6, 0), 3, 7);
return 0; return 0;
} }
@ -426,8 +479,10 @@ static int ceata_wait_idle(void)
{ {
uint32_t status; uint32_t status;
PASS_RC(mmc_fastio_read(0xf, &status), 1, 0); PASS_RC(mmc_fastio_read(0xf, &status), 1, 0);
if (!(status & 0x88)) return 0; if (!(status & 0x88))
if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(1); return 0;
if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT))
RET_ERR(1);
sleep(HZ / 20); 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, | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count), direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count),
NULL, CEATA_COMMAND_TIMEOUT), 3, 0); 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) if (semaphore_wait(&mmc_wakeup, timeout) == OBJ_WAIT_TIMEDOUT)
{ {
PASS_RC(ceata_cancel_command(), 3, 1); 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_DVR, 0);
ata_write_cbr(&ATA_PIO_CSD, CMD_IDENTIFY); ata_write_cbr(&ATA_PIO_CSD, CMD_IDENTIFY);
PASS_RC(ata_wait_for_start_of_transfer(10000000), 1, 1); 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; return 0;
} }
@ -548,6 +605,34 @@ static int ata_set_feature(uint32_t feature, uint32_t param)
return 0; 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 * ATA_UDMA_TIME register is documented on s3c6400 datasheet, information
* included in s5l8700 datasheet is wrong or not valid for s5l8702. * included in s5l8700 datasheet is wrong or not valid for s5l8702.
@ -572,10 +657,10 @@ static int ata_power_up(void)
ata_set_active(); ata_set_active();
ide_power_enable(true); ide_power_enable(true);
long spinup_start = current_tick; long spinup_start = current_tick;
if (ceata) if (ceata) {
{
ata_lba48 = true; ata_lba48 = true;
ata_dma = true; ata_dma = true;
dma_mode = 0xff; /* Canary */
PCON(8) = 0x33333333; PCON(8) = 0x33333333;
PCON(9) = 0x00000033; PCON(9) = 0x00000033;
PCON(11) |= 0xf; PCON(11) |= 0xf;
@ -596,10 +681,7 @@ static int ata_power_up(void)
sleep(HZ / 100); sleep(HZ / 100);
PASS_RC(ceata_init(8), 3, 1); PASS_RC(ceata_init(8), 3, 1);
PASS_RC(ata_identify(ata_identify_data), 3, 2); PASS_RC(ata_identify(ata_identify_data), 3, 2);
dma_mode = 0x44; } else {
}
else
{
PCON(7) = 0x44444444; PCON(7) = 0x44444444;
PCON(8) = 0x44444444; PCON(8) = 0x44444444;
PCON(9) = 0x44444444; PCON(9) = 0x44444444;
@ -619,64 +701,35 @@ static int ata_power_up(void)
ATA_PIO_LHR = 0; ATA_PIO_LHR = 0;
ATA_CFG = BIT(6); ATA_CFG = BIT(6);
while (!(ATA_PIO_READY & BIT(1))) yield(); while (!(ATA_PIO_READY & BIT(1))) yield();
PASS_RC(ata_identify(ata_identify_data), 3, 3); PASS_RC(ata_identify(ata_identify_data), 3, 3);
uint32_t piotime = 0x11f3;
uint32_t mdmatime = 0x1c175; uint32_t piotime = 0x11f3; /* PIO0-2? */
uint32_t udmatime = 0x4071152; if (ata_identify_data[53] & BIT(1)) /* Word 64..70 valid */
{
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 */
}
ATA_PIO_TIME = piotime;
uint32_t param = 0; uint32_t param = 0;
ata_dma_flags = 0; ata_dma_flags = 0;
ata_lba48 = ata_identify_data[83] & BIT(10) ? true : false; #ifdef HAVE_ATA_DMA
if (ata_identify_data[53] & BIT(1)) if ((ata_identify_data[53] & BIT(2)) && (ata_identify_data[88] & BITRANGE(0, 4))) /* Any UDMA */
{ {
if (ata_identify_data[64] & BIT(1)) piotime = 0x2072; param = ata_get_best_mode(ata_identify_data[88], ATA_MAX_UDMA, 0x40);
else if (ata_identify_data[64] & BIT(0)) piotime = 0x7083; ATA_UDMA_TIME = udmatimes[param & 0xf];
ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10);
} }
if (ata_identify_data[63] & BIT(2)) if (!param && ata_identify_data[63] & BITRANGE(0, 2)) /* Fall back to any MWDMA */
{
mdmatime = 0x5072;
param = 0x22;
}
else if (ata_identify_data[63] & BIT(1))
{
mdmatime = 0x7083;
param = 0x21;
}
if (ata_identify_data[63] & BITRANGE(0, 2))
{ {
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); 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; ata_dma = param ? true : false;
dma_mode = param; dma_mode = param;
PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ 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 */ PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */
if (ata_identify_data[83] & BIT(9)) if (ata_identify_data[83] & BIT(9))
PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ 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; spinup_time = current_tick - spinup_start;
if (ata_lba48)
ata_total_sectors = ata_identify_data[100] ata_total_sectors = (ata_identify_data[61] << 16) | ata_identify_data[60];
| (((uint64_t)ata_identify_data[101]) << 16) if ( ata_identify_data[83] & BIT(10) && ata_total_sectors == 0x0FFFFFFF)
| (((uint64_t)ata_identify_data[102]) << 32) {
| (((uint64_t)ata_identify_data[103]) << 48); ata_total_sectors = ((uint64_t)ata_identify_data[103] << 48) |
else ((uint64_t)ata_identify_data[102] << 32) |
ata_total_sectors = ata_identify_data[60] | (((uint32_t)ata_identify_data[61]) << 16); ((uint64_t)ata_identify_data[101] << 16) |
ata_total_sectors >>= 3; /* ie SECTOR_SIZE/512. */ ata_identify_data[100];
ata_lba48 = true;
} else {
ata_lba48 = false;
}
ata_total_sectors >>= SIZE_SHIFT;
ata_powered = true; ata_powered = true;
ata_set_active(); ata_set_active();
return 0; return 0;
@ -708,7 +764,8 @@ static int ata_power_up(void)
static void ata_power_down(void) static void ata_power_down(void)
{ {
if (!ata_powered) return; if (!ata_powered)
return;
if (ceata) if (ceata)
{ {
memset(ceata_taskfile, 0, 16); memset(ceata_taskfile, 0, 16);
@ -727,7 +784,8 @@ static void ata_power_down(void)
ata_wait_for_rdy(1000000); ata_wait_for_rdy(1000000);
sleep(HZ / 30); sleep(HZ / 30);
ATA_CONTROL = 0; ATA_CONTROL = 0;
while (!(ATA_CONTROL & BIT(1))) yield(); while (!(ATA_CONTROL & BIT(1)))
yield();
PWRCON(0) |= (1 << 5); PWRCON(0) |= (1 << 5);
} }
PCON(7) = 0; PCON(7) = 0;
@ -744,18 +802,18 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo
if (ceata) if (ceata)
{ {
memset(ceata_taskfile, 0, 16); memset(ceata_taskfile, 0, 16);
ceata_taskfile[0x2] = cnt >> 5; ceata_taskfile[0x2] = cnt >> (8-SIZE_SHIFT);
ceata_taskfile[0x3] = sector >> 21; ceata_taskfile[0x3] = sector >> (24-SIZE_SHIFT);
ceata_taskfile[0x4] = sector >> 29; ceata_taskfile[0x4] = sector >> (32-SIZE_SHIFT);
ceata_taskfile[0x5] = sector >> 37; ceata_taskfile[0x5] = sector >> (40-SIZE_SHIFT);
ceata_taskfile[0xa] = cnt << 3; ceata_taskfile[0xa] = cnt << SIZE_SHIFT;
ceata_taskfile[0xb] = sector << 3; ceata_taskfile[0xb] = sector << SIZE_SHIFT;
ceata_taskfile[0xc] = sector >> 5; ceata_taskfile[0xc] = sector >> (8-SIZE_SHIFT);
ceata_taskfile[0xd] = sector >> 13; ceata_taskfile[0xd] = sector >> (16-SIZE_SHIFT);
ceata_taskfile[0xf] = write ? CMD_WRITE_DMA_EXT : CMD_READ_DMA_EXT; ceata_taskfile[0xf] = write ? CMD_WRITE_DMA_EXT : CMD_READ_DMA_EXT;
PASS_RC(ceata_wait_idle(), 2, 0); PASS_RC(ceata_wait_idle(), 2, 0);
PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1); 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 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); ata_write_cbr(&ATA_PIO_DVR, 0);
if (ata_lba48) if (ata_lba48)
{ {
ata_write_cbr(&ATA_PIO_SCR, cnt >> 5); ata_write_cbr(&ATA_PIO_SCR, (cnt >> (8-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff); ata_write_cbr(&ATA_PIO_SCR, (cnt << SIZE_SHIFT) & 0xff);
ata_write_cbr(&ATA_PIO_LHR, (sector >> 37) & 0xff); ata_write_cbr(&ATA_PIO_LHR, (sector >> (40-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LMR, (sector >> 29) & 0xff); ata_write_cbr(&ATA_PIO_LMR, (sector >> (32-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LLR, (sector >> 21) & 0xff); ata_write_cbr(&ATA_PIO_LLR, (sector >> (24-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff); ata_write_cbr(&ATA_PIO_LHR, (sector >> (16-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff); ata_write_cbr(&ATA_PIO_LMR, (sector >> (8-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff); ata_write_cbr(&ATA_PIO_LLR, (sector << SIZE_SHIFT) & 0xff);
ata_write_cbr(&ATA_PIO_DVR, BIT(6)); ata_write_cbr(&ATA_PIO_DVR, BIT(6));
if (write) if (write)
ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_WRITE_DMA_EXT : CMD_WRITE_MULTIPLE_EXT); 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 else
{ {
ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff); ata_write_cbr(&ATA_PIO_SCR, (cnt << SIZE_SHIFT) & 0xff);
ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff); ata_write_cbr(&ATA_PIO_LHR, (sector >> (16-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff); ata_write_cbr(&ATA_PIO_LMR, (sector >> (8-SIZE_SHIFT)) & 0xff);
ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff); ata_write_cbr(&ATA_PIO_LLR, (sector << SIZE_SHIFT) & 0xff);
ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 21) & 0xf)); ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> (24-SIZE_SHIFT)) & 0xf));
if (write) if (write)
ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_WRITE_DMA : CMD_WRITE_SECTORS); ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_WRITE_DMA : CMD_WRITE_SECTORS);
else else
ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_READ_DMA : CMD_READ_MULTIPLE); ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_READ_DMA : CMD_READ_MULTIPLE);
} }
#ifdef HAVE_ATA_DMA
if (ata_dma) if (ata_dma)
{ {
PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1); 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 = BITRANGE(0, 4);
ATA_IRQ_MASK = BIT(0); ATA_IRQ_MASK = BIT(0);
ATA_COMMAND = BIT(0); ATA_COMMAND = BIT(0);
if (semaphore_wait(&ata_wakeup, 500000 * HZ / 1000000) if (semaphore_wait(&ata_wakeup, 500000 * HZ / 1000000) == OBJ_WAIT_TIMEDOUT)
== OBJ_WAIT_TIMEDOUT)
{ {
ATA_COMMAND = BIT(1); ATA_COMMAND = BIT(1);
ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); 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)); ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
} }
else else
#endif // HAVE_ATA_DMA
{ {
cnt *= SECTOR_SIZE / 512; cnt <<= SIZE_SHIFT;
while (cnt--) while (cnt--)
{ {
int i; int i;
@ -834,7 +893,7 @@ static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bo
else else
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR); ((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); 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) 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)) if (STORAGE_OVERLAP((uint32_t)buffer))
{ {
while (count) while (count)
@ -871,19 +931,27 @@ static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool wr
return 0; return 0;
} }
#endif
if (!ata_powered) ata_power_up(); if (!ata_powered)
if (sector + count > ata_total_sectors) RET_ERR(0); ata_power_up();
if (sector + count > ata_total_sectors)
RET_ERR(0);
ata_set_active(); ata_set_active();
if (ata_dma && write) commit_dcache(); if (ata_dma && write)
else if (ata_dma) commit_discard_dcache(); commit_dcache();
if (!ceata) ATA_COMMAND = BIT(1); else if (ata_dma)
commit_discard_dcache();
if (!ceata)
ATA_COMMAND = BIT(1);
while (count) 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; int rc = -1;
rc = ata_rw_chunk(sector, cnt, buffer, write); 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) if (rc && ata_retries)
{ {
void* buf = buffer; 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) while (tries-- && rc)
{ {
rc = ata_rw_chunk(sect, 1, buf, write); 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; buf += SECTOR_SIZE;
} }
} }
@ -915,9 +985,13 @@ int ata_soft_reset(void)
{ {
int rc; int rc;
mutex_lock(&ata_mutex); 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(); ata_set_active();
if (ceata) rc = ceata_soft_reset(); if (ceata)
{
rc = ceata_soft_reset();
}
else else
{ {
ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2)); ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2));
@ -944,7 +1018,8 @@ static int ata_reset(void)
{ {
int rc; int rc;
mutex_lock(&ata_mutex); 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(); ata_set_active();
rc = ata_soft_reset(); rc = ata_soft_reset();
if (IS_ERR(rc)) if (IS_ERR(rc))
@ -956,7 +1031,8 @@ static int ata_reset(void)
ata_power_down(); ata_power_down();
sleep(HZ * 3); sleep(HZ * 3);
int rc2 = ata_power_up(); 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; else rc = 1;
} }
@ -1036,14 +1112,21 @@ void ata_spin(void)
ata_set_active(); ata_set_active();
} }
#ifdef STORAGE_GET_INFO
void ata_get_info(IF_MD(int drive,) struct storage_info *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).num_sectors = ata_total_sectors;
(*info).vendor = "Apple"; (*info).vendor = "Apple";
(*info).product = "iPod Classic"; (*info).product = "iPod Classic";
(*info).revision = "1.0"; (*info).revision = "1.0";
} }
#endif
long ata_last_disk_activity(void) long ata_last_disk_activity(void)
{ {
@ -1064,7 +1147,8 @@ int ata_init(void)
mutex_lock(&ata_mutex); mutex_lock(&ata_mutex);
int rc = ata_power_up(); int rc = ata_power_up();
mutex_unlock(&ata_mutex); mutex_unlock(&ata_mutex);
if (IS_ERR(rc)) return rc; if (IS_ERR(rc))
return rc;
return 0; 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_DVR, BIT(6));
ata_write_cbr(&ATA_PIO_CSD, CMD_SMART); ata_write_cbr(&ATA_PIO_CSD, CMD_SMART);
PASS_RC(ata_wait_for_start_of_transfer(10000000), 3, 7); 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(); ata_set_active();
return 0; return 0;
@ -1136,24 +1221,29 @@ int ata_spinup_time(void)
return spinup_time; return spinup_time;
} }
#ifdef HAVE_ATA_DMA
int ata_get_dma_mode(void) int ata_get_dma_mode(void)
{ {
return dma_mode; return dma_mode;
} }
#endif
void INT_ATA(void) void INT_ATA(void)
{ {
uint32_t ata_irq = ATA_IRQ; uint32_t ata_irq = ATA_IRQ;
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; ATA_IRQ_MASK = 0;
} }
void INT_MMC(void) void INT_MMC(void)
{ {
uint32_t irq = SDCI_IRQ; uint32_t irq = SDCI_IRQ;
if (irq & SDCI_IRQ_DAT_DONE_INT) semaphore_release(&mmc_wakeup); if (irq & SDCI_IRQ_DAT_DONE_INT)
if (irq & SDCI_IRQ_IOCARD_IRQ_INT) semaphore_release(&mmc_comp_wakeup); semaphore_release(&mmc_wakeup);
if (irq & SDCI_IRQ_IOCARD_IRQ_INT)
semaphore_release(&mmc_comp_wakeup);
SDCI_IRQ = irq; SDCI_IRQ = irq;
} }