//----------------------------------------------------------------------------- bool SdioCard::readData(uint8_t *dst) { DBG_IRQSTAT(); uint32_t *p32 = reinterpret_cast<uint32_t*>(dst); if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) { SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ; if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) { // Don't stop at block gap if last block. Allows auto CMD12. SDHC_PROCTL |= SDHC_PROCTL_CREQ; } else { noInterrupts(); SDHC_PROCTL |= SDHC_PROCTL_CREQ; SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; interrupts(); } } if (waitTimeout(isBusyFifoRead)) { return sdError(SD_CARD_ERROR_READ_FIFO); } for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) { while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) { } for (uint32_t i = 0; i < FIFO_WML; i++) { p32[i] = SDHC_DATPORT; } p32 += FIFO_WML; } if (waitTimeout(isBusyTransferComplete)) { return sdError(SD_CARD_ERROR_READ_TIMEOUT); } m_irqstat = SDHC_IRQSTAT; SDHC_IRQSTAT = m_irqstat; return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); }
//----------------------------------------------------------------------------- bool SdioCard::writeData(const uint8_t* src) { DBG_IRQSTAT(); const uint32_t* p32 = reinterpret_cast<const uint32_t*>(src); if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) { SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ; // Don't stop at block gap if last block. Allows auto CMD12. if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) { SDHC_PROCTL |= SDHC_PROCTL_CREQ; } else { SDHC_PROCTL |= SDHC_PROCTL_CREQ; SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; } } if (waitTimeout(isBusyFifoWrite)) { return sdError(SD_CARD_ERROR_WRITE_FIFO); } for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) { while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) { } for (uint32_t i = 0; i < FIFO_WML; i++) { SDHC_DATPORT = p32[i]; } p32 += FIFO_WML; } if (waitTimeout(isBusyTransferComplete)) { return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); } m_irqstat = SDHC_IRQSTAT; SDHC_IRQSTAT = m_irqstat; return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); }
//----------------------------------------------------------------------------- bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) { // check for single block erase if (!m_csd.v1.erase_blk_en) { // erase size mask uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low; if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { // error card can't erase specified area return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); } } if (!m_highCapacity) { firstBlock <<= 9; lastBlock <<= 9; } if (!cardCommand(CMD32_XFERTYP, firstBlock)) { return sdError(SD_CARD_ERROR_CMD32); } if (!cardCommand(CMD33_XFERTYP, lastBlock)) { return sdError(SD_CARD_ERROR_CMD33); } if (!cardCommand(CMD38_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD38); } if (waitTimeout(isBusyCMD13)) { return sdError(SD_CARD_ERROR_ERASE_TIMEOUT); } return true; }
//------------------------------------------------------------------------------ // zero FAT and root dir area on SD void clearFatDir(uint32_t bgn, uint32_t count) { clearCache(false); if (!card.writeStart(bgn, count)) { sdError("Clear FAT/DIR writeStart failed"); } for (uint32_t i = 0; i < count; i++) { if ((i & 0XFF) == 0) cout << '.'; if (!card.writeData(cache.data)) { sdError("Clear FAT/DIR writeData failed"); } } if (!card.writeStop()) { sdError("Clear FAT/DIR writeStop failed"); } cout << endl; }
//----------------------------------------------------------------------------- static bool rdWrBlocks(uint32_t xfertyp, uint32_t lba, uint8_t* buf, size_t n) { if ((3 & (uint32_t)buf) || n == 0) { return sdError(SD_CARD_ERROR_DMA); } if (yieldTimeout(isBusyCMD13)) { return sdError(SD_CARD_ERROR_CMD13); } enableDmaIrs(); SDHC_DSADDR = (uint32_t)buf; SDHC_CMDARG = m_highCapacity ? lba : 512*lba; SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512); SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK; SDHC_XFERTYP = xfertyp; return waitDmaStatus(); }
bool staticDataAdd(StaticData *self, StaticDataId id, void *object) { if (self->locked) { sdError(self, "StaticData has been locked and cannot be modified anymore."); return false; } StaticDataKey key; staticDataGenKey(self, id, key); if (zhash_insert(self->hashtable, key, object) != 0) { sdError(self, "Cannot insert the object '%s'", key); return false; } return true; }
//----------------------------------------------------------------------------- static bool cardCMD6(uint32_t arg, uint8_t* status) { // CMD6 returns 64 bytes. if (waitTimeout(isBusyCMD13)) { return sdError(SD_CARD_ERROR_CMD13); } enableDmaIrs(); SDHC_DSADDR = (uint32_t)status; SDHC_CMDARG = arg; SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64); SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK; SDHC_XFERTYP = CMD6_XFERTYP; if (!waitDmaStatus()) { return sdError(SD_CARD_ERROR_CMD6); } return true; }
//----------------------------------------------------------------------------- // SDHC will do Auto CMD12 after count blocks. bool SdioCard::readStart(uint32_t lba, uint32_t count) { DBG_IRQSTAT(); if (count > 0XFFFF) { return sdError(SD_CARD_ERROR_READ_START); } if (yieldTimeout(isBusyCMD13)) { return sdError(SD_CARD_ERROR_CMD13); } if (count > 1) { SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; } SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) { return sdError(SD_CARD_ERROR_CMD18); } return true; }
//----------------------------------------------------------------------------- bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) { uint8_t aligned[512]; uint8_t* ptr = (uint32_t)buf & 3 ? aligned : buf; if (!rdWrBlocks(CMD17_DMA_XFERTYP, lba, ptr, 1)) { return sdError(SD_CARD_ERROR_CMD18); } if (ptr != buf) { memcpy(buf, aligned, 512); } return true; }
//----------------------------------------------------------------------------- static bool transferStop() { DBG_IRQSTAT(); if (!cardCommand(CMD12_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD12); } if (yieldTimeout(isBusyCMD13)) { return sdError(SD_CARD_ERROR_CMD13); } // Save registers before reset DAT lines. uint32_t irqsststen = SDHC_IRQSTATEN; uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ; // Do reset to clear CDIHB. Should be a better way! SDHC_SYSCTL |= SDHC_SYSCTL_RSTD; // Restore registers. SDHC_IRQSTATEN = irqsststen; SDHC_PROCTL = proctl; return true; }
//----------------------------------------------------------------------------- bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) { if ((uint32_t)buf & 3) { for (size_t i = 0; i < n; i++, lba++, buf += 512) { if (!readBlock(lba, buf)) { return false; // readBlock will set errorCode. } } return true; } if (!rdWrBlocks(CMD18_DMA_XFERTYP, lba, buf, n)) { return sdError(SD_CARD_ERROR_CMD18); } return true; }
bool staticDataInit(StaticData *self, char *name) { memset(self, 0, sizeof(StaticData)); self->locked = false; self->name = strdup(name); if (!(self->hashtable = zhash_new())) { sdError(self, "Cannot allocate a new hashtable."); return false; } return true; }
bool staticDataGet(StaticData *self, StaticDataId id, void *_out, bool emitError) { void **out = _out; if (!self->locked) { sdError(self, "StaticData should have been locked before querying it."); return false; } StaticDataKey key; staticDataGenKey(self, id, key); void *object = NULL; if (!(object = zhash_lookup(self->hashtable, key))) { if (emitError) { sdError(self, "Cannot find the static data for object '%s'", key); } return false; } *out = object; return true; }
//----------------------------------------------------------------------------- bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) { uint8_t *ptr; uint8_t aligned[512]; if (3 & (uint32_t)buf) { ptr = aligned; memcpy(aligned, buf, 512); } else { ptr = const_cast<uint8_t*>(buf); } if (!rdWrBlocks(CMD24_DMA_XFERTYP, lba, ptr, 1)) { return sdError(SD_CARD_ERROR_CMD24); } return true; }
//----------------------------------------------------------------------------- bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) { uint8_t* ptr = const_cast<uint8_t*>(buf); if (3 & (uint32_t)ptr) { for (size_t i = 0; i < n; i++, lba++, ptr += 512) { if (!writeBlock(lba, ptr)) { return false; // writeBlock will set errorCode. } } return true; } if (!rdWrBlocks(CMD25_DMA_XFERTYP, lba, ptr, n)) { return sdError(SD_CARD_ERROR_CMD25); } return true; }
//------------------------------------------------------------------------------ // format and write the Master Boot Record void writeMbr() { clearCache(true); part_t* p = cache.mbr.part; p->boot = 0; uint16_t c = lbnToCylinder(relSector); if (c > 1023) sdError("MBR CHS"); p->beginCylinderHigh = c >> 8; p->beginCylinderLow = c & 0XFF; p->beginHead = lbnToHead(relSector); p->beginSector = lbnToSector(relSector); p->type = partType; uint32_t endLbn = relSector + partSize - 1; c = lbnToCylinder(endLbn); if (c <= 1023) { p->endCylinderHigh = c >> 8; p->endCylinderLow = c & 0XFF; p->endHead = lbnToHead(endLbn); p->endSector = lbnToSector(endLbn); } else {
//------------------------------------------------------------------------------ // initialize appropriate sizes for SD capacity void initSizes() { if (cardCapacityMB <= 6) { sdError("Card is too small."); } else if (cardCapacityMB <= 16) { sectorsPerCluster = 2; } else if (cardCapacityMB <= 32) { sectorsPerCluster = 4; } else if (cardCapacityMB <= 64) { sectorsPerCluster = 8; } else if (cardCapacityMB <= 128) { sectorsPerCluster = 16; } else if (cardCapacityMB <= 1024) { sectorsPerCluster = 32; } else if (cardCapacityMB <= 32768) { sectorsPerCluster = 64; } else { // SDXC cards sectorsPerCluster = 128; } cout << pstr("Blocks/Cluster: ") << int(sectorsPerCluster) << endl; // set fake disk geometry sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63; if (cardCapacityMB <= 16) { numberOfHeads = 2; } else if (cardCapacityMB <= 32) { numberOfHeads = 4; } else if (cardCapacityMB <= 128) { numberOfHeads = 8; } else if (cardCapacityMB <= 504) { numberOfHeads = 16; } else if (cardCapacityMB <= 1008) { numberOfHeads = 32; } else if (cardCapacityMB <= 2016) { numberOfHeads = 64; } else if (cardCapacityMB <= 4032) { numberOfHeads = 128; } else { numberOfHeads = 255; } }
//----------------------------------------------------------------------------- bool SdioCard::writeStart(uint32_t lba) { // K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode. return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED); }
//============================================================================= bool SdioCard::begin() { uint32_t kHzSdClk; uint32_t arg; m_initDone = false; m_errorCode = SD_CARD_ERROR_NONE; m_highCapacity = false; m_version2 = false; // initialize controller. initSDHC(); if (!cardCommand(CMD0_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD0); } // Try several times for case of reset delay. for (uint32_t i = 0; i < CMD8_RETRIES; i++) { if (cardCommand(CMD8_XFERTYP, 0X1AA)) { if (SDHC_CMDRSP0 != 0X1AA) { return sdError(SD_CARD_ERROR_CMD8); } m_version2 = true; break; } } arg = m_version2 ? 0X40300000 : 0x00300000; uint32_t m = micros(); do { if (!cardAcmd(0, ACMD41_XFERTYP, arg) || ((micros() - m) > BUSY_TIMEOUT_MICROS)) { return sdError(SD_CARD_ERROR_ACMD41); } } while ((SDHC_CMDRSP0 & 0x80000000) == 0); m_ocr = SDHC_CMDRSP0; if (SDHC_CMDRSP0 & 0x40000000) { // Is high capacity. m_highCapacity = true; } if (!cardCommand(CMD2_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD2); } if (!cardCommand(CMD3_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD3); } m_rca = SDHC_CMDRSP0 & 0xFFFF0000; if (!readReg16(CMD9_XFERTYP, &m_csd)) { return sdError(SD_CARD_ERROR_CMD9); } if (!readReg16(CMD10_XFERTYP, &m_cid)) { return sdError(SD_CARD_ERROR_CMD10); } if (!cardCommand(CMD7_XFERTYP, m_rca)) { return sdError(SD_CARD_ERROR_CMD7); } // Set card to bus width four. if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { return sdError(SD_CARD_ERROR_ACMD6); } // Set SDHC to bus width four. SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK; SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML); // Determine if High Speed mode is supported and set frequency. uint8_t status[64]; if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { kHzSdClk = 50000; } else { kHzSdClk = 25000; } // disable GPIO enableGPIO(false); // Set the SDHC SCK frequency. setSdclk(kHzSdClk); // enable GPIO enableGPIO(true); m_initDone = true; return true; }