/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2007 Dave Chapman * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ //#define LOGF_ENABLE #include "config.h" #include "storage.h" #include "timer.h" #include "kernel.h" #include "string.h" #include "power.h" #include "panic.h" #include "mmcdefs-target.h" #include "s5l87xx.h" #include "led.h" #include "debug.h" #include "panic.h" #include "fs_defines.h" #include "logf.h" #ifndef ATA_RETRIES #define ATA_RETRIES 3 #endif #define CMD_READ_SECTORS 0x20 #define CMD_READ_DMA_EXT 0x25 #define CMD_READ_MULTIPLE_EXT 0x29 #define CMD_WRITE_SECTORS 0x30 #define CMD_WRITE_DMA_EXT 0x35 #define CMD_WRITE_MULTIPLE_EXT 0x39 #ifdef HAVE_ATA_SMART #define CMD_SMART 0xB0 #endif #define CMD_READ_MULTIPLE 0xC4 #define CMD_WRITE_MULTIPLE 0xC5 #define CMD_READ_DMA 0xC8 #define CMD_WRITE_DMA 0xCA #define CMD_STANDBY_IMMEDIATE 0xE0 #define CMD_FLUSH_CACHE 0xE7 #define CMD_FLUSH_CACHE_EXT 0xEA #define CMD_IDENTIFY 0xEC #define CMD_SET_FEATURES 0xEF #define CEATA_POWERUP_TIMEOUT 20000000 #define CEATA_COMMAND_TIMEOUT 1000000 #define CEATA_DAT_NONBUSY_TIMEOUT 5000000 #define CEATA_MMC_RCA 1 /** static, private data **/ static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR; static uint16_t identify_info[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR; static bool ceata; static bool ata_lba48; static bool ata_dma; static uint64_t ata_total_sectors; static uint32_t log_sector_size; static struct mutex ata_mutex; static struct semaphore ata_wakeup; static long ata_last_activity_value = -1; static long ata_sleep_timeout = 7 * HZ; static bool ata_powered; static bool canflush = true; static struct semaphore mmc_wakeup; static struct semaphore mmc_comp_wakeup; static int spinup_time = 0; #ifdef HAVE_ATA_DMA static int dma_mode = 0; static uint32_t ata_dma_flags; #endif 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) { while (!(ATA_PIO_READY & 2)); volatile uint32_t dummy __attribute__((unused)) = *reg; while (!(ATA_PIO_READY & 1)); return ATA_PIO_RDATA; } static void ata_write_cbr(uint32_t volatile* reg, uint16_t data) { while (!(ATA_PIO_READY & 2)); *reg = data; } static int ata_wait_for_not_bsy(long timeout) { long startusec = USEC_TIMER; 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); yield(); } } static int ata_wait_for_rdy(long timeout) { long startusec = USEC_TIMER; PASS_RC(ata_wait_for_not_bsy(timeout), 1, 0); 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); yield(); } } static int ata_wait_for_start_of_transfer(long timeout) { long startusec = USEC_TIMER; PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0); 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); yield(); } } 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; RET_ERR(2); } 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 (!disable_crc) if (dsta & SDCI_DSTA_RESCRCE) rc |= 8; if (rc) RET_ERR(rc); return 0; } static bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int timeout) { 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); yield(); } SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3 | SDCI_STAC_CLR_RESEND | SDCI_STAC_CLR_DATEND | SDCI_STAC_CLR_DAT_CRCEND | SDCI_STAC_CLR_CRC_STAEND | SDCI_STAC_CLR_RESTOUTE | SDCI_STAC_CLR_RESENDE | SDCI_STAC_CLR_RESINDE | SDCI_STAC_CLR_RESCRCE | SDCI_STAC_CLR_WR_DATCRCE | SDCI_STAC_CLR_RD_DATCRCE | SDCI_STAC_CLR_RD_DATENDE0 | SDCI_STAC_CLR_RD_DATENDE1 | SDCI_STAC_CLR_RD_DATENDE2 | SDCI_STAC_CLR_RD_DATENDE3 | SDCI_STAC_CLR_RD_DATENDE4 | SDCI_STAC_CLR_RD_DATENDE5 | 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); SDCI_CMD = cmd | SDCI_CMD_CMDSTR; long sleepbase = USEC_TIMER; while (TIMEOUT_EXPIRED(sleepbase, 1000)) yield(); while (!(SDCI_DSTA & SDCI_DSTA_CMDEND)) { 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); 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); 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; return 0; } static int mmc_get_card_status(uint32_t* result) { return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_STATUS) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SEND_STATUS_RCA(CEATA_MMC_RCA), result, CEATA_COMMAND_TIMEOUT); } static int mmc_init(void) { sleep(HZ / 10); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_GO_IDLE_STATE) | SDCI_CMD_CMD_TYPE_BC | SDCI_CMD_RES_TYPE_NONE | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID, 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 0); long startusec = USEC_TIMER; uint32_t result; do { 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 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID, MMC_CMD_SEND_OP_COND_OCR(MMC_OCR_270_360), NULL, CEATA_COMMAND_TIMEOUT), 3, 2); result = SDCI_RESP0; } while (!(result & MMC_OCR_POWER_UP_DONE)); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_ALL_SEND_CID) | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R2 | SDCI_CMD_RES_SIZE_136 | SDCI_CMD_NCR_NID_NID, 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 3); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SET_RELATIVE_ADDR) | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SET_RELATIVE_ADDR_RCA(CEATA_MMC_RCA), NULL, CEATA_COMMAND_TIMEOUT), 3, 4); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SELECT_CARD) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, 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); return 0; } static int mmc_fastio_write(uint32_t addr, uint32_t data) { return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_WRITE | MMC_CMD_FAST_IO_ADDRESS(addr) | MMC_CMD_FAST_IO_DATA(data), NULL, CEATA_COMMAND_TIMEOUT); } static int mmc_fastio_read(uint32_t addr, uint32_t* data) { return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_READ | MMC_CMD_FAST_IO_ADDRESS(addr), data, CEATA_COMMAND_TIMEOUT); } static int ceata_soft_reset(void) { PASS_RC(mmc_fastio_write(6, 4), 2, 0); sleep(HZ / 100); PASS_RC(mmc_fastio_write(6, 0), 2, 1); sleep(HZ / 100); long startusec = USEC_TIMER; uint32_t status; do { PASS_RC(mmc_fastio_read(0xf, &status), 2, 2); if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(3); sleep(HZ / 100); } while (status & 0x80); return 0; } static int mmc_dsta_check_data_success(void) { int rc = 0; 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_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); return 0; } static void mmc_discard_irq(void) { SDCI_IRQ = SDCI_IRQ_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT | SDCI_IRQ_MASK_MASK_READ_WAIT_INT; semaphore_wait(&mmc_wakeup, 0); } static int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size) { if (size > 0x10) RET_ERR(0); mmc_discard_irq(); SDCI_DMASIZE = size; SDCI_DMACOUNT = 1; SDCI_DMAADDR = dest; SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; commit_discard_dcache(); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG) | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ | 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); PASS_RC(mmc_dsta_check_data_success(), 2, 3); return 0; } static int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size) { uint32_t i; if (size > 0x10) RET_ERR(0); mmc_discard_irq(); SDCI_DMASIZE = size; SDCI_DMACOUNT = 0; SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG) | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc) | 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]; long startusec = USEC_TIMER; 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); yield(); } PASS_RC(mmc_dsta_check_data_success(), 3, 4); return 0; } static int ceata_init(int buswidth) { uint32_t result; 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, MMC_CMD_SWITCH_ACCESS_WRITE_BYTE | 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 (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; 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, MMC_CMD_SWITCH_ACCESS_WRITE_BYTE | 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 (buswidth == 4) SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT; else if (buswidth == 8) SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_8BIT; } 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); PASS_RC(mmc_fastio_write(6, 0), 3, 7); return 0; } static int ceata_check_error(void) { uint32_t status, error; PASS_RC(mmc_fastio_read(0xf, &status), 2, 0); if (status & 1) { PASS_RC(mmc_fastio_read(0x9, &error), 2, 1); RET_ERR((error << 2) | 2); } return 0; } static int ceata_wait_idle(void) { long startusec = USEC_TIMER; while (true) { 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); sleep(HZ / 20); } } static int ceata_cancel_command(void) { GPIOCMD = 0x9000e; udelay(1); GPIOCMD = 0x9000f; udelay(1); GPIOCMD = 0x90003; udelay(1); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_STOP_TRANSMISSION) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, 0, NULL, CEATA_COMMAND_TIMEOUT), 1, 0); PASS_RC(ceata_wait_idle(), 1, 1); return 0; } static int ceata_rw_multiple_block(bool write, void* buf, uint32_t count, long timeout) { mmc_discard_irq(); uint32_t responsetype; uint32_t cmdtype; uint32_t direction; if (write) { cmdtype = SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR; responsetype = SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY; direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE; } else { cmdtype = SDCI_CMD_CMD_TYPE_ADTC; responsetype = SDCI_CMD_RES_TYPE_R1; direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ; } SDCI_DMASIZE = 0x200; SDCI_DMAADDR = buf; SDCI_DMACOUNT = count; SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; commit_discard_dcache(); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_BLOCK) | SDCI_CMD_CMD_TYPE_ADTC | cmdtype | responsetype | 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 (semaphore_wait(&mmc_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) { PASS_RC(ceata_cancel_command(), 3, 1); RET_ERR(2); } PASS_RC(mmc_dsta_check_data_success(), 3, 3); if (semaphore_wait(&mmc_comp_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) { PASS_RC(ceata_cancel_command(), 3, 4); RET_ERR(5); } PASS_RC(ceata_check_error(), 3, 6); return 0; } static int ata_identify(uint16_t* buf) { int i; if (ceata) { memset(ceata_taskfile, 0, 16); ceata_taskfile[0xf] = CMD_IDENTIFY; 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(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2); } else { PASS_RC(ata_wait_for_not_bsy(10000000), 1, 0); 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); } return 0; } static void ata_set_active(void) { ata_last_activity_value = current_tick; } bool ata_disk_is_active(void) { return ata_powered; } static int ata_set_feature(uint32_t feature, uint32_t param) { if (ceata) { memset(ceata_taskfile, 0, 16); ceata_taskfile[0x1] = feature; ceata_taskfile[0x2] = param; ceata_taskfile[0xf] = CMD_SET_FEATURES; PASS_RC(ceata_wait_idle(), 2, 0); PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1); PASS_RC(ceata_wait_idle(), 2, 2); } else { PASS_RC(ata_wait_for_rdy(2000000), 2, 0); ata_write_cbr(&ATA_PIO_DVR, 0); ata_write_cbr(&ATA_PIO_FED, feature); ata_write_cbr(&ATA_PIO_SCR, param); ata_write_cbr(&ATA_PIO_CSD, CMD_SET_FEATURES); PASS_RC(ata_wait_for_rdy(2000000), 2, 1); } return 0; } #ifdef HAVE_ATA_DMA static int udmatimes[ATA_MAX_UDMA + 1] = { 0x4071152, 0x2050d52, #if ATA_MAX_UDMA >= 2 0x2030a52, #endif #if ATA_MAX_UDMA >= 3 0x1020a52, #endif #if ATA_MAX_UDMA >= 4 0x1010a52, #endif }; 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. * * On Classic (boosted): * HClk = 108 MHz. -> T = ~9.26 ns. * * Configured values (in nanoseconds): * * UDMA ATA_UDMA_TIME tACK tRP tSS tDVS tDVH Tcyc WR(MB/s) * 0 0x4071152 27.8 166.7 55.6 74.1 46.3 120.4 16.6 * 1 0x2050d52 27.8 129.6 55.6 55.6 27.8 83.4 24 * 2 0x2030a52 27.8 101.8 55.6 37 27.8 64.8 30.9 * 3 0x1020a52 27.8 101.8 55.6 27.8 18.5 46.3 43.2 * 4 0x1010a52 27.8 101.8 55.6 18.5 18.5 37 54 * * Tcyc = tDVS+tDVH * WR[bytes/s] = 1/Tcyc[s] * 2[bytes] */ static int ata_power_up(void) { logf("ata POWERUP %ld", current_tick); ata_set_active(); ide_power_enable(true); long spinup_start = current_tick; if (ceata) { ata_lba48 = true; ata_dma = true; #ifdef HAVE_ATA_DMA dma_mode = 0xff; /* Canary */ #endif PCON(8) = 0x33333333; PCON(9) = 0x00000033; PCON(11) |= 0xf; ATA_UNKNOWN = 0; ATA_CONTROL = 0; PWRCON(0) &= ~(1 << 9); SDCI_RESET = 0xa5; sleep(HZ / 100); GPIOUNK380 = 0; PUNK8 = 0xff; SDCI_CTRL = SDCI_CTRL_SDCIEN | SDCI_CTRL_CLK_SEL_SDCLK | SDCI_CTRL_BIT_8 | SDCI_CTRL_BIT_14; SDCI_CLKDIV = SDCI_CDIV_CLKDIV(260); GPIOCMD = 0xb000f; SDCI_IRQ_MASK = SDCI_IRQ_MASK_MASK_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT; PASS_RC(mmc_init(), 3, 0); SDCI_CLKDIV = SDCI_CDIV_CLKDIV(4); sleep(HZ / 100); PASS_RC(ceata_init(8), 3, 1); PASS_RC(ata_identify(identify_info), 3, 2); } else { PCON(7) = 0x44444444; PCON(8) = 0x44444444; PCON(9) = 0x44444444; PCON(10) = (PCON(10) & ~0xffff) | 0x4444; PWRCON(0) &= ~(1 << 5); ATA_CFG = BIT(0); sleep(HZ / 100); ATA_CFG = 0; sleep(HZ / 100); ATA_SWRST = BIT(0); sleep(HZ / 100); ATA_SWRST = 0; sleep(HZ / 10); ATA_CONTROL = BIT(0); sleep(HZ / 5); ATA_PIO_TIME = 0x191f7; ATA_PIO_LHR = 0; ATA_CFG = BIT(6); while (!(ATA_PIO_READY & BIT(1))) yield(); PASS_RC(ata_identify(identify_info), 3, 3); uint32_t piotime = 0x11f3; /* PIO0-2? */ if (identify_info[53] & BIT(1)) /* Word 64..70 valid */ { if (identify_info[64] & BIT(1)) piotime = 0x2072; /* PIO mode 4 */ else if (identify_info[64] & BIT(0)) piotime = 0x7083; /* PIO mode 3 */ } ATA_PIO_TIME = piotime; uint32_t param = 0; #ifdef HAVE_ATA_DMA ata_dma_flags = 0; if ((identify_info[53] & BIT(2)) && (identify_info[88] & BITRANGE(0, 4))) /* Any UDMA */ { int max_udma = ATA_MAX_UDMA; #if ATA_MAX_UDMA > 2 if (!identify_info[76] && !(identify_info[93] & BIT(13))) /* w93b13 is only valid for PATA, w76 is 0 PATA */ max_udma = 2; #endif param = ata_get_best_mode(identify_info[88], max_udma, 0x40); ATA_UDMA_TIME = udmatimes[param & 0xf]; ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10); } if (!param && identify_info[63] & BITRANGE(0, 2)) /* Fall back to any MWDMA */ { param = ata_get_best_mode(identify_info[63], ATA_MAX_MWDMA, 0x20); ATA_MDMA_TIME = mwdmatimes[param & 0xf]; ata_dma_flags = BIT(3) | BIT(10); } dma_mode = param; #endif /* HAVE_ATA_DMA */ ata_dma = param ? true : false; PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ /* SET_FEATURE only supported on PATA, not CE-ATA */ if (identify_info[82] & BIT(5)) PASS_RC(ata_set_feature(0x02, 0), 3, 5); /* Enable volatile write cache */ if (identify_info[82] & BIT(6)) PASS_RC(ata_set_feature(0xaa, 0), 3, 6); /* Enable read lookahead */ if (identify_info[83] & BIT(3)) PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */ if (identify_info[83] & BIT(9)) PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ PASS_RC(ata_identify(identify_info), 3, 9); /* Finally, re-read identify info */ } spinup_time = current_tick - spinup_start; ata_total_sectors = (identify_info[61] << 16) | identify_info[60]; if (ceata || (identify_info[83] & BIT(10) && ata_total_sectors == 0x0FFFFFFF)) { ata_total_sectors = ((uint64_t)identify_info[103] << 48) | ((uint64_t)identify_info[102] << 32) | ((uint64_t)identify_info[101] << 16) | identify_info[100]; ata_lba48 = true; } else { ata_lba48 = false; } ata_powered = true; ata_set_active(); return 0; } static void ata_power_down(void) { if (!ata_powered) return; logf("ata POWERDOWN %ld", current_tick); PCON(7) = 0; PCON(8) = 0; PCON(9) = 0; PCON(10) &= ~0xffff; PCON(11) &= ~0xf; ide_power_enable(false); ata_powered = false; } static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bool write) { if (ceata) { memset(ceata_taskfile, 0, 16); ceata_taskfile[0x2] = cnt >> 8; ceata_taskfile[0x3] = sector >> 24; ceata_taskfile[0x4] = sector >> 32; ceata_taskfile[0x5] = sector >> 40; ceata_taskfile[0xa] = cnt; ceata_taskfile[0xb] = sector; ceata_taskfile[0xc] = sector >> 8; ceata_taskfile[0xd] = sector >> 16; 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, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2); } else { PASS_RC(ata_wait_for_rdy(100000), 2, 0); ata_write_cbr(&ATA_PIO_DVR, 0); if (ata_lba48) { ata_write_cbr(&ATA_PIO_SCR, (cnt >> 8) & 0xff); ata_write_cbr(&ATA_PIO_SCR, (cnt) & 0xff); ata_write_cbr(&ATA_PIO_LHR, (sector >> 40) & 0xff); ata_write_cbr(&ATA_PIO_LMR, (sector >> 32) & 0xff); ata_write_cbr(&ATA_PIO_LLR, (sector >> 24) & 0xff); ata_write_cbr(&ATA_PIO_LHR, (sector >> 16) & 0xff); ata_write_cbr(&ATA_PIO_LMR, (sector >> 8) & 0xff); ata_write_cbr(&ATA_PIO_LLR, (sector) & 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); else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? CMD_READ_DMA_EXT : CMD_READ_MULTIPLE_EXT); } else { ata_write_cbr(&ATA_PIO_SCR, (cnt) & 0xff); ata_write_cbr(&ATA_PIO_LHR, (sector >> 16) & 0xff); ata_write_cbr(&ATA_PIO_LMR, (sector >> 8) & 0xff); ata_write_cbr(&ATA_PIO_LLR, (sector) & 0xff); ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 24) & 0xf)); /* LBA28, mask off upper 4 bits of 32-bit sector address */ 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); if (write) { ATA_SBUF_START = buffer; ATA_SBUF_SIZE = log_sector_size * cnt; ATA_CFG |= BIT(4); } else { ATA_TBUF_START = buffer; ATA_TBUF_SIZE = log_sector_size * cnt; ATA_CFG &= ~BIT(4); } ATA_XFR_NUM = log_sector_size * cnt - 1; ATA_CFG |= ata_dma_flags; ATA_CFG &= ~(BIT(7) | BIT(8)); semaphore_wait(&ata_wakeup, 0); 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) { ATA_COMMAND = BIT(1); ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); RET_ERR(2); } ATA_COMMAND = BIT(1); ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); } else #endif // HAVE_ATA_DMA { while (cnt--) { uint16_t i; PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1); if (write) for (i = 0; i < log_sector_size/2; i++) ata_write_cbr(&ATA_PIO_DTR, ((uint16_t*)buffer)[i]); else for (i = 0; i < log_sector_size/2; i++) ((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR); buffer += log_sector_size; } } PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 3); } return 0; } static int ata_rw_chunk(uint64_t sector, uint32_t cnt, void* buffer, bool write) { led(true); int rc = ata_rw_chunk_internal(sector, cnt, buffer, write); led(false); return rc; } static int ata_transfer_sectors(uint64_t sector, uint32_t count, void* buffer, bool write) { 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); logf("ata XFER (%d) %d @ %llu", write, count, sector); while (count) { uint32_t cnt = MIN(ata_lba48 ? 65536 : 256, count); int rc = -1; rc = ata_rw_chunk(sector, cnt, buffer, write); if (rc && ata_error_srst) ata_reset(); if (rc && ata_retries) { void* buf = buffer; uint64_t sect; for (sect = sector; sect < sector + cnt; sect++) { rc = -1; int tries = ata_retries; while (tries-- && rc) { rc = ata_rw_chunk(sect, 1, buf, write); if (rc && ata_error_srst) ata_reset(); } if (rc) break; buf += log_sector_size; } } PASS_RC(rc, 1, 1); buffer += log_sector_size * cnt; sector += cnt; count -= cnt; } ata_set_active(); return 0; } /* API Functions */ int ata_soft_reset(void) { int rc; mutex_lock(&ata_mutex); if (!ata_powered) PASS_RC(ata_power_up(), 1, 0); ata_set_active(); if (ceata) { rc = ceata_soft_reset(); } else { ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2)); udelay(10); ata_write_cbr(&ATA_PIO_DAD, 0); rc = ata_wait_for_rdy(3000000); } ata_set_active(); mutex_unlock(&ata_mutex); PASS_RC(rc, 1, 1); return 0; } int ata_hard_reset(void) { mutex_lock(&ata_mutex); PASS_RC(ata_power_up(), 0, 0); ata_set_active(); mutex_unlock(&ata_mutex); return 0; } static int ata_reset(void) { int rc; mutex_lock(&ata_mutex); if (!ata_powered) PASS_RC(ata_power_up(), 2, 0); ata_set_active(); rc = ata_soft_reset(); if (IS_ERR(rc)) { rc = ata_hard_reset(); if (IS_ERR(rc)) { rc = ERR_RC((rc << 2) | 1); ata_power_down(); sleep(HZ * 3); int rc2 = ata_power_up(); if (IS_ERR(rc2)) rc = ERR_RC((rc << 2) | 2); } else rc = 1; } ata_set_active(); mutex_unlock(&ata_mutex); return rc; } #include "ata-common.c" #ifndef MAX_PHYS_SECTOR_SIZE int ata_read_sectors(IF_MD(int drive,) sector_t start, int incount, void* inbuf) { #ifdef HAVE_MULTIDRIVE (void)drive; /* unused for now */ #endif mutex_lock(&ata_mutex); int rc = ata_transfer_sectors(start, incount, inbuf, false); mutex_unlock(&ata_mutex); return rc; } int ata_write_sectors(IF_MD(int drive,) sector_t start, int count, const void* outbuf) { #ifdef HAVE_MULTIDRIVE (void)drive; /* unused for now */ #endif mutex_lock(&ata_mutex); int rc = ata_transfer_sectors(start, count, (void*)((uint32_t)outbuf), true); mutex_unlock(&ata_mutex); return rc; } #endif /* ndef MAX_PHYS_SECTOR_SIZE */ void ata_spindown(int seconds) { ata_sleep_timeout = seconds * HZ; } static void ata_flush_cache(void) { uint8_t cmd; logf("ata FLUSH CACHE %ld", current_tick); if (ceata) { memset(ceata_taskfile, 0, 16); ceata_taskfile[0xf] = CMD_FLUSH_CACHE_EXT; /* CE-ATA only supports EXT */ ceata_wait_idle(); ceata_write_multiple_register(0, ceata_taskfile, 16); ceata_wait_idle(); } else { if (!canflush) { return; } else if (ata_lba48 && identify_info[83] & BIT(13)) { cmd = CMD_FLUSH_CACHE_EXT; /* Flag, optional, ATA-6 and up, for use with LBA48 devices. Mandatory for CE-ATA */ } else if (identify_info[83] & BIT(12)) { cmd = CMD_FLUSH_CACHE; /* Flag, mandatory, ATA-6 and up */ } else if (identify_info[80] >= BIT(5)) { /* Use >= instead of '&' because bits lower than the latest standard we support don't have to be set */ cmd = CMD_FLUSH_CACHE; /* No flag, mandatory, ATA-5 (Optional for ATA-4) */ } else { /* If neither command is supported then don't issue it. */ canflush = 0; return; } ata_wait_for_rdy(1000000); ata_write_cbr(&ATA_PIO_DVR, 0); ata_write_cbr(&ATA_PIO_CSD, cmd); ata_wait_for_rdy(1000000); } } int ata_flush(void) { if (ata_powered) { mutex_lock(&ata_mutex); ata_flush_cache(); mutex_unlock(&ata_mutex); } return 0; } void ata_sleepnow(void) { mutex_lock(&ata_mutex); ata_flush_cache(); if (ceata || ata_disk_can_sleep()) { logf("ata SLEEP %ld", current_tick); if (ceata) { memset(ceata_taskfile, 0, 16); ceata_taskfile[0xf] = CMD_STANDBY_IMMEDIATE; ceata_wait_idle(); ceata_write_multiple_register(0, ceata_taskfile, 16); ceata_wait_idle(); sleep(HZ); PWRCON(0) |= (1 << 9); } else { ata_wait_for_rdy(1000000); ata_write_cbr(&ATA_PIO_DVR, 0); ata_write_cbr(&ATA_PIO_CSD, CMD_STANDBY_IMMEDIATE); ata_wait_for_rdy(1000000); sleep(HZ / 30); ATA_CONTROL = 0; while (!(ATA_CONTROL & BIT(1))) yield(); PWRCON(0) |= (1 << 5); } } if (ceata || ata_disk_can_sleep() || canflush) ata_power_down(); // XXX add a powerdown delay similar to main ATA driver? mutex_unlock(&ata_mutex); } 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 = log_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) { return ata_last_activity_value; } int ata_init(void) { mutex_init(&ata_mutex); semaphore_init(&ata_wakeup, 1, 0); semaphore_init(&mmc_wakeup, 1, 0); semaphore_init(&mmc_comp_wakeup, 1, 0); ceata = PDAT(11) & BIT(1); ata_powered = false; ata_total_sectors = 0; /* get identify_info */ mutex_lock(&ata_mutex); int rc = ata_power_up(); /* Includes identify() call */ mutex_unlock(&ata_mutex); if (IS_ERR(rc)) return rc; /* Logical sector size */ if (ceata) log_sector_size = 1 << identify_info[106]; else if ((identify_info[106] & 0xd000) == 0x5000) /* B14, B12 */ log_sector_size = (identify_info[117] | (identify_info[118] << 16)) * 2; else log_sector_size = 512; #ifndef MAX_VARIABLE_LOG_SECTOR if (log_sector_size != SECTOR_SIZE) panicf("Bad logical sector size (%ld)", log_sector_size); #else if (log_sector_size > MAX_VARIABLE_LOG_SECTOR) panicf("Logical sector size too large (%ld)", log_sector_size); #endif #ifdef MAX_PHYS_SECTOR_SIZE rc = ata_get_phys_sector_mult(); if (IS_ERR(rc)) return rc; #endif return 0; } #ifdef HAVE_ATA_SMART static int ata_smart(uint16_t* buf, uint8_t cmd) { if (!ata_powered) PASS_RC(ata_power_up(), 3, 0); if (ceata) { memset(ceata_taskfile, 0, 16); ceata_taskfile[0xc] = 0x4f; ceata_taskfile[0xd] = 0xc2; ceata_taskfile[0xe] = BIT(6); ceata_taskfile[0xf] = CMD_SMART; PASS_RC(ceata_wait_idle(), 3, 1); if (((uint8_t*)identify_info)[54] != 'A') /* Model != aAmsung */ { ceata_taskfile[0x9] = 0xd8; /* SMART enable operations */ PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 2); PASS_RC(ceata_check_error(), 3, 3); } ceata_taskfile[0x9] = cmd; PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 4); PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 3, 5); } else { int i; PASS_RC(ata_wait_for_not_bsy(10000000), 3, 6); ata_write_cbr(&ATA_PIO_FED, cmd); ata_write_cbr(&ATA_PIO_LMR, 0x4f); ata_write_cbr(&ATA_PIO_LHR, 0xc2); 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); } ata_set_active(); return 0; } int ata_read_smart(struct ata_smart_values* smart_data, uint8_t cmd) { mutex_lock(&ata_mutex); int rc = ata_smart((uint16_t*)smart_data, cmd); mutex_unlock(&ata_mutex); return rc; } #endif /* HAVE_ATA_SMART */ #ifdef CONFIG_STORAGE_MULTI static int ata_num_drives(int first_drive) { /* We don't care which logical drive number(s) we have been assigned */ (void)first_drive; return 1; } #endif unsigned short* ata_get_identify(void) { return identify_info; } 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); 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); SDCI_IRQ = irq; } int ata_event(long id, intptr_t data) { int rc = 0; /* GCC does a lousy job culling unreachable cases in the default handler if statements are in a switch statement, so we'll do it this way. Only the first case is frequently hit anyway. */ if (LIKELY(id == Q_STORAGE_TICK)) { if (!ata_powered || TIME_BEFORE(current_tick, ata_last_activity_value + ata_sleep_timeout)) { STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); } } else if (id == Q_STORAGE_SLEEPNOW) { ata_sleepnow(); } else if (id == Q_STORAGE_SLEEP) { ata_last_activity_value = current_tick - ata_sleep_timeout + HZ / 5; } else if (id == SYS_USB_CONNECTED) { STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); } else { rc = storage_event_default_handler(id, data, ata_last_activity_value, STORAGE_ATA); } return rc; }