static sdmmc_rt sdmmc_acmd(int nr, uint32_t arg) { sdmmc_rt r; r = sdmmc_cmd(CMD55R1_APP_CMD, sd_sm->rca << 16); if (r != SDMMC_OK) { printk("SDMMC status = 0x%.8X\n", sdmmc_resp()); return r; } //sdmmc_print_r1(); return sdmmc_cmd(nr, arg); }
static sdmmc_rt CMD1(void) { sdmmc_rt r; uint32_t ocr, msk; ocr = OCR_VOLTAGE_WINDOW(BUS_POWER_VOLTAGE); msk = OCR_PowerUpEnd; do { r = sdmmc_cmd(CMD1R3_SEND_OP_COND, ocr & ~OCR_PowerUpEnd); if (r != SDMMC_OK) { printk("MMCPROT\tcards with non compatible voltage range\n"); return r; } ocr = sdmmc_resp(); if ((ocr & msk) == msk) break; printk("MMCPROT\tcard is busy or\n"); printk("\thost omitted voltage range\n"); sd_sm->ci_stat = SDP_IDLE; } while (AM18X_TRUE); if (ocr & MOCR_VOLTAGE_165to195) { printk("MMCPROT\tLow Voltage MultiMediaCard\n"); } else { printk("MMCPROT\tHigh Voltage MultiMediaCard\n"); } printk("%s() ocr = 0x%.8X\n", __func__, ocr); if (0 == (ocr & OCR_VOLTAGE_WINDOW(BUS_POWER_VOLTAGE))) { return SDMMC_UNSUP; } return SDMMC_OK; }
int sdmmc_write_multiple_blocks(uint32_t address, uint32_t n_blocks, uint8_t (*next_byte)()) { int result; int i; if ((result = sdmmc_cmd(25, block_addressing ? address : address << 9)) < 0) { cs_high(); return result; } spi(0xff); // initiate write while (n_blocks--) { spi(0xfc); // data token for (i = 0; i < 512; i++) { // sector data spi(next_byte()); } spi(0xff); // CRC spi(0xff); result = spi(0xff); // data response if ((result & 0x1f) != 0x05) { cs_high(); return result; } i = 0; do { // wait while card is busy if (++i == 131072) { cs_high(); return -10; } } while (spi(0xff) != 0xff); } return sdmmc_stop_transmission(); }
int sdmmc_read_block(uint32_t address, uint8_t *buffer) { int i; int result; // CMD17 - READ_SINGLE_BLOCK result = sdmmc_cmd(17, block_addressing ? address : address << 9); if (result < 0) { cs_high(); return -1; } // wait for data token for (i = 0; i < TOKEN_COUNT; i++) { if (spi(0xff) == 0xfe) { break; } } if (i == TOKEN_COUNT) { return -2; } // read data for (i = 0; i < 512; i++) { *buffer++ = spi(0xff); } // skip CRC spi(0xff); spi(0xff); sdmmc_cmd_term(); return 0; }
int sdmmc_stop_transmission() { int result; if ((result = sdmmc_cmd(12, 0)) < 0) { while (spi(0xff) != 0xff); cs_high(); return result; } return 0; }
int sdmmc_read_multiple_blocks_start(uint32_t address) { int result; if ((result = sdmmc_cmd(18, block_addressing ? address : address << 9)) < 0) { cs_high(); return result; } return 0; }
// Protocol // 4.2.3 Card Initialization and Identification Process static sdmmc_rt sdmmc_card_init(void) { sdmmc_rt r; int i; sd_sm->rca = 0; sd_sm->is_mmc = 0; sd_sm->is_bus4bit = 0; sd_sm->ci_stat = SDP_IDLE; for (i = 0; i < 1000; i++); sdmmc_cmd_noarg(CMD0_GO_IDLE_STATE); printk("SDPROT\tIdle State(idle)\n"); r = sdmmc_cmd(CMD8R7_SEND_IF_COND, CMD8_VHS_27to36 | CMD8_CHECK_PATTERN); printk("SDMMC cmd8() %s\n", sdmmc_err_string(r)); if (r == SDMMC_NO_RSP) { printk("SDPROT\tVer2.00 or later SD Memory Card(voltage mismatch)\n"); printk("\tor Ver1.X SD Memory Card\n"); printk("\tor not SD Memory Card\n"); } else if ((sdmmc_resp() & CMD8_CHECK_PATTERN_MASK) == CMD8_CHECK_PATTERN) { printk("SDPROT\tVer2.00 or later SD Memory Card\n"); } else { // unsupported return SDMMC_UNSUP; } if ((r = ACMD41()) == SDMMC_OK) { printk("SDPROT\tCard returns ready\n"); printk("\tVer1.X Standard Capacity SD Memory Card\n"); } else { printk("SDPROT\tNo Response(Non valid command)\n"); printk("\tMust be a MultiMediaCard\n"); printk("SDPORT\tStart MultiMediaCard initialization process\n"); printk("\tstarting at CMD1\n"); if ((r = CMD1()) != SDMMC_OK) { return r; } sd_sm->is_mmc = 1; sd_sm->rca = MMC_RCA; } printk("SDPROT\tReady State(ready)\n"); for (i = 0; i < SDMMC_CMD_RETRY; i++) { r = sdmmc_cmd_noarg(CMD2R2_ALL_SEND_CID); if (r == SDMMC_OK) break; } if (r != SDMMC_OK) { return r; } printk("SDPROT\tIdentification State(ident)\n"); sdmmc_get_cid(); // sdprot_print_cid(&sd_sm->cid); for (i = 0; i < SDMMC_CMD_RETRY; i++) { uint32_t arg = 0; if (sd_sm->is_mmc) { arg = sd_sm->rca << 16; } r = sdmmc_cmd(CMD3R6_SEND_RELATIVE, arg); if (r == SDMMC_OK) break; } if (r != SDMMC_OK) { return r; } printk("SDPROT\tCard responds with new RCA\n"); if (!sd_sm->is_mmc) { sd_sm->rca = (sdmmc_resp() >> 16); }
static inline sdmmc_rt sdmmc_cmd_noarg(int nr) { return sdmmc_cmd(nr, SDMMC_ARG_NULL); }
int sdmmc_init() { int i; int result; // send > 74 clock pulses with CS = DI = 1 cs_high(); for (i = 0; i < 10; i++) { spi(0xff); } // CMD0 - GO_IDLE_STATE result = sdmmc_cmd(0, 0); sdmmc_cmd_term(); if (result != 0x01) { return -1; } // CMD8 - SEND_IF_COND result = sdmmc_cmd(8, 0x1aa); if (result != 0x01) { // TODO: initialize SD v1 or MMC v3 sdmmc_cmd_term(); return -2; } if ((result = sdmmc_read_word()) != 0x1aa) { sdmmc_cmd_term(); return -3; } sdmmc_cmd_term(); for (i = 0; i < CMD41_COUNT; i++) { // CMD55 - APP_CMD result = sdmmc_cmd(55, 0); sdmmc_cmd_term(); if (result < 0) { return -5; } // CMD41 - APP_SEND_OP_COND result = sdmmc_cmd(41, 0x40000000); sdmmc_cmd_term(); if (result == 0x00) { break; } else if (result != 0x01) { return -6; } } if (i == CMD41_COUNT) { return -7; } // CMD58 - READ_OCR result = sdmmc_cmd(58, 0); if (result < 0) { sdmmc_cmd_term(); return -8; } if ((result = sdmmc_read_word()) & 0x40000000) { block_addressing = 1; } else { block_addressing = 0; sdmmc_cmd_term(); // CMD16 - SET_BLOCK_LEN (512 bytes) result = sdmmc_cmd(16, 512); if (result < 0) { sdmmc_cmd_term(); return -9; } } sdmmc_cmd_term(); return 0; }