rt_int32_t mmcsd_go_idle(struct rt_mmcsd_host *host) { rt_int32_t err; struct rt_mmcsd_cmd cmd; if (!controller_is_spi(host)) { mmcsd_set_chip_select(host, MMCSD_CS_HIGH); mmcsd_delay_ms(1); } rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = GO_IDLE_STATE; cmd.arg = 0; cmd.flags = RESP_SPI_R1 | RESP_NONE | CMD_BC; err = mmcsd_send_cmd(host, &cmd, 0); mmcsd_delay_ms(1); if (!controller_is_spi(host)) { mmcsd_set_chip_select(host, MMCSD_CS_IGNORE); mmcsd_delay_ms(1); } return err; }
static rt_int32_t _mmcsd_select_card(struct rt_mmcsd_host *host, struct rt_mmcsd_card *card) { rt_int32_t err; struct rt_mmcsd_cmd cmd; rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SELECT_CARD; if (card) { cmd.arg = card->rca << 16; cmd.flags = RESP_R1 | CMD_AC; } else { cmd.arg = 0; cmd.flags = RESP_NONE | CMD_AC; } err = mmcsd_send_cmd(host, &cmd, 3); if (err) return err; return 0; }
static rt_err_t mmcsd_app_cmd(struct rt_mmcsd_host *host, struct rt_mmcsd_card *card) { rt_err_t err; struct rt_mmcsd_cmd cmd = {0}; cmd.cmd_code = APP_CMD; if (card) { cmd.arg = card->rca << 16; cmd.flags = RESP_R1 | CMD_AC; } else { cmd.arg = 0; cmd.flags = RESP_R1 | CMD_BCR; } err = mmcsd_send_cmd(host, &cmd, 0); if (err) return err; /* Check that card supported application commands */ if (!controller_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) return -RT_ERROR; return RT_EOK; }
int mmcsd_init_seq(int *r7) { int r, i; mmcsd_deselect(); for (i = 0; i < 10; ++i) spi_read(DUMMY_BYTE); delay_ms(10); mmcsd_select(); r = 0; r = mmcsd_go_idle_state(TRUE); mmcsd_deselect(); if (r != 0x01) return 0xFF; i = 0; do { delay_ms(10); mmcsd_select(); r = 0; r = mmcsd_sd_send_cmd(SEND_IF_COND, IF_CONDITION_PASS, TRUE, r7); mmcsd_deselect(); i++; if (i == 0xFF) return RESP_TIMEOUT; } while (make16(r7[1], r7[0]) != IF_CONDITION_PASS); i = 0; do { delay_ms(10); mmcsd_select(); r = 0; r = mmcsd_app_send_op_cond(OP_CONDITION, TRUE); mmcsd_deselect(); i++; if (i == 0xFF) return RESP_TIMEOUT; } while (r != 0); i = 0; do { delay_ms(10); mmcsd_select(); mmcsd_send_cmd(CRC_ON_OFF, 0, TRUE); r = 0xFF; r = mmcsd_get_r7(r7); mmcsd_deselect(); i++; if (i == 0xFF) return RESP_TIMEOUT; } while (bit_test(r, 0)); return r; }
rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *cmd5_resp) { struct rt_mmcsd_cmd cmd; rt_int32_t i, err = 0; RT_ASSERT(host != RT_NULL); rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_IO_SEND_OP_COND; cmd.arg = ocr; cmd.flags = RESP_SPI_R4 | RESP_R4 | CMD_BCR; for (i = 100; i; i--) { err = mmcsd_send_cmd(host, &cmd, 0); if (err) break; /* if we're just probing, do a single pass */ if (ocr == 0) break; /* otherwise wait until reset completes */ if (controller_is_spi(host)) { /* * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate * an initialized card under SPI, but some cards * (Marvell's) only behave when looking at this * one. */ if (cmd.resp[1] & CARD_BUSY) break; } else { if (cmd.resp[0] & CARD_BUSY) break; } err = -RT_ETIMEOUT; mmcsd_delay_ms(10); } if (cmd5_resp) *cmd5_resp = cmd.resp[controller_is_spi(host) ? 1 : 0]; return err; }
rt_int32_t mmcsd_spi_use_crc(struct rt_mmcsd_host *host, rt_int32_t use_crc) { struct rt_mmcsd_cmd cmd; rt_int32_t err; rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SPI_CRC_ON_OFF; cmd.flags = RESP_SPI_R1; cmd.arg = use_crc; err = mmcsd_send_cmd(host, &cmd, 0); if (!err) host->spi_use_crc = use_crc; return err; }
rt_int32_t mmcsd_spi_read_ocr(struct rt_mmcsd_host *host, rt_int32_t high_capacity, rt_uint32_t *ocr) { struct rt_mmcsd_cmd cmd; rt_int32_t err; rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SPI_READ_OCR; cmd.arg = high_capacity ? (1 << 30) : 0; cmd.flags = RESP_SPI_R3; err = mmcsd_send_cmd(host, &cmd, 0); *ocr = cmd.resp[1]; return err; }
rt_int32_t mmcsd_all_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid) { rt_int32_t err; struct rt_mmcsd_cmd cmd; rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = ALL_SEND_CID; cmd.arg = 0; cmd.flags = RESP_R2 | CMD_BCR; err = mmcsd_send_cmd(host, &cmd, 3); if (err) return err; rt_memcpy(cid, cmd.resp, sizeof(rt_uint32_t) * 4); return 0; }
rt_err_t mmcsd_get_card_addr(struct rt_mmcsd_host *host, rt_uint32_t *rca) { rt_err_t err; struct rt_mmcsd_cmd cmd; rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = RESP_R6 | CMD_BCR; err = mmcsd_send_cmd(host, &cmd, 3); if (err) return err; *rca = cmd.resp[0] >> 16; return RT_EOK; }
rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card, rt_int32_t rw, rt_uint32_t fn, rt_uint32_t reg_addr, rt_uint8_t *pdata, rt_uint8_t raw) { struct rt_mmcsd_cmd cmd; rt_int32_t err; RT_ASSERT(card != RT_NULL); RT_ASSERT(fn <= SDIO_MAX_FUNCTIONS); if (reg_addr & ~SDIO_ARG_CMD53_REG_MASK) return -RT_ERROR; rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_IO_RW_DIRECT; cmd.arg = rw ? SDIO_ARG_CMD52_WRITE : SDIO_ARG_CMD52_READ; cmd.arg |= fn << SDIO_ARG_CMD52_FUNC_SHIFT; cmd.arg |= raw ? SDIO_ARG_CMD52_RAW_FLAG : 0x00000000; cmd.arg |= reg_addr << SDIO_ARG_CMD52_REG_SHIFT; cmd.arg |= *pdata; cmd.flags = RESP_SPI_R5 | RESP_R5 | CMD_AC; err = mmcsd_send_cmd(card->host, &cmd, 0); if (err) return err; if (!controller_is_spi(card->host)) { if (cmd.resp[0] & R5_ERROR) return -RT_EIO; if (cmd.resp[0] & R5_FUNCTION_NUMBER) return -RT_ERROR; if (cmd.resp[0] & R5_OUT_OF_RANGE) return -RT_ERROR; } if (!rw || raw) { if (controller_is_spi(card->host)) *pdata = (cmd.resp[0] >> 8) & 0xFF; else *pdata = cmd.resp[0] & 0xFF; }
/* * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND * before SD_APP_OP_COND. This command will harmlessly fail for * SD 1.0 cards. */ rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr) { struct rt_mmcsd_cmd cmd; rt_err_t err; rt_uint8_t pattern; cmd.cmd_code = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | 0xAA; cmd.flags = RESP_SPI_R7 | RESP_R7 | CMD_BCR; err = mmcsd_send_cmd(host, &cmd, 0); if (err) return err; if (controller_is_spi(host)) pattern = cmd.resp[1] & 0xFF; else pattern = cmd.resp[0] & 0xFF; if (pattern != 0xAA) return -RT_ERROR; return RT_EOK; }
int mmcsd_sd_send_op_cond(short crc_check) { mmcsd_send_cmd(SD_SEND_OP_COND, 0, crc_check); return mmcsd_get_r1(); }
static sdmmc_rt sdmmc_cmd(int nr, uint32_t arg) { sdcard_response_t srt; mmcsd_cmd_t cmd; uint32_t stat; sdmmc_rt r; int i; r = SDMMC_OK; cmd.index = nr; cmd.arg = arg; if (sdprot_next_stat(nr, sd_sm->ci_stat) == SDP_INV) { printk("SDPROT\tCurrent State %s with CMD%d\n", sdprot_stat_name(sd_sm->ci_stat), nr); // r = SDMMC_UNSUP; // goto done; } cmd.cflags = 0; switch(srt = sdprot_resp_type(nr)) { case SDCARD_48BIT_RSP: cmd.cflags |= MMCSD_CMD_F_RSP | MMCSD_CMD_F_SHORT; if (sdprot_resp_crc(nr)) { cmd.cflags |= MMCSD_CMD_F_CRC; } break; case SDCARD_136BIT_RSP: cmd.cflags |= MMCSD_CMD_F_RSP | MMCSD_CMD_F_LONG; break; case SDCARD_NONE_RSP: default: cmd.cflags |= MMCSD_CMD_F_NORSP; break; } if (sdprot_need_data(nr) != SDPROT_NO_DATA) { cmd.cflags |= MMCSD_CMD_F_DATA; if (sdprot_need_data(nr) == SDPROT_READ_DATA) { cmd.cflags |= MMCSD_CMD_F_READ; } else { cmd.cflags |= MMCSD_CMD_F_WRITE; // am1808 bug fix // cmd.cflags &= ~(MMCSD_CMD_F_RSP | MMCSD_CMD_F_LONG); } } if (sdprot_need_busy(nr)) { cmd.cflags |= MMCSD_CMD_F_BUSY; } mmcsd_send_cmd(MMCSDCON, &cmd); for(i = 0;;) { stat = sdmmc_cmd_stat(nr); if (stat == MMCSD_SC_RSP_TOUT || stat == MMCSD_SC_RSP_OK || stat == MMCSD_SC_CRC_ERR) { break; } if (i++ > SDMMC_REG_RETRY) { printk("%s() *** error stat = %d ***\n", __func__, stat); r = SDMMC_NO_RSP; goto done; } } if (stat != MMCSD_SC_RSP_OK) { printk("*** MMCCMD=0x%.8X ARG=0x%.8X ***", MMCSDCON->MMCCMD, MMCSDCON->MMCARGHL); printk(" *** ST0=0x%.8X RSP=0x%.8X ***\n", MMCSDCON->MMCST0, MMCSDCON->MMCRSP[3]); } if (stat == MMCSD_SC_CRC_ERR) { r = SDMMC_CRC_ERR; goto done; } if (stat == MMCSD_SC_RSP_TOUT) { r = SDMMC_NO_RSP; goto done; } printk("SDPROT\tCMD%d OK\n", nr); stat = sdprot_next_stat(nr, sd_sm->ci_stat); if (stat != sd_sm->ci_stat) { printk("SDPROT\tTransition from %s to %s\n", sdprot_stat_name(sd_sm->ci_stat), sdprot_stat_name(stat)); sd_sm->ci_stat = stat; } done: return r; }
rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd) { rt_int32_t err, i; struct rt_mmcsd_req req; struct rt_mmcsd_cmd cmd; struct rt_mmcsd_data data; rt_uint32_t *buf = RT_NULL; if (!controller_is_spi(card->host)) { rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SEND_CSD; cmd.arg = card->rca << 16; cmd.flags = RESP_R2 | CMD_AC; err = mmcsd_send_cmd(card->host, &cmd, 3); if (err) return err; rt_memcpy(csd, cmd.resp, sizeof(rt_uint32_t) * 4); return 0; } buf = (rt_uint32_t*)rt_malloc(16); if (!buf) { rt_kprintf("allocate memory failed\n"); return -RT_ENOMEM; } rt_memset(&req, 0, sizeof(struct rt_mmcsd_req)); rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); rt_memset(&data, 0, sizeof(struct rt_mmcsd_data)); req.cmd = &cmd; req.data = &data; cmd.cmd_code = SEND_CSD; cmd.arg = 0; /* NOTE HACK: the RESP_SPI_R1 is always correct here, but we * rely on callers to never use this with "native" calls for reading * CSD or CID. Native versions of those commands use the R2 type, * not R1 plus a data block. */ cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC; data.blksize = 16; data.blks = 1; data.flags = DATA_DIR_READ; data.buf = buf; /* * The spec states that CSR and CID accesses have a timeout * of 64 clock cycles. */ data.timeout_ns = 0; data.timeout_clks = 64; mmcsd_send_request(card->host, &req); if (cmd.err || data.err) { rt_free(buf); return -RT_ERROR; } for (i = 0;i < 4;i++) csd[i] = buf[i]; rt_free(buf); return 0; }
int mmcsd_set_blocken(long long address, long size) { mmcsd_send_cmd(SET_BLOCKLEN, size, FALSE); return mmcsd_get_r1(); }
int mmcsd_write_single_block(long long address) { mmcsd_send_cmd(WRITE_BLOCK, address, FALSE); return mmcsd_get_r1(); }
int mmcsd_go_idle_state(short crc_check) { mmcsd_send_cmd(GO_IDLE_STATE, 0, crc_check); return mmcsd_get_r1(); }
int mmcsd_read_single_block(long long address) { mmcsd_send_cmd(READ_SINGLE_BLOCK, address, FALSE); return mmcsd_get_r1(); }
int mmcsd_read_ocr(short crc_check, int *r3) { mmcsd_send_cmd(READ_OCR, 0, crc_check); return mmcsd_get_r3(r3); }
int mmcsd_app_send_op_cond(long long arg, short crc_check) { mmcsd_app_cmd(crc_check); mmcsd_send_cmd(41, arg, crc_check); return mmcsd_get_r1(); }
int mmcsd_sd_send_cmd(int cmd, long long arg, short crc_check, int *r7) { mmcsd_send_cmd(cmd, arg, crc_check); return mmcsd_get_r7(r7); }
int mmcsd_app_cmd(short crc_check) { mmcsd_send_cmd(APP_CMD, 0, crc_check); return mmcsd_get_r1(); }
int mmcsd_send_if_cond(short crc_check) { mmcsd_send_cmd(SEND_IF_COND, 0, crc_check); return mmcsd_get_r1(); }