/* * \brief Identify card * * Does currently not work! Report all card types being present, * no matter what and if any card is actually inserted! * * This is according to TI TRM */ void mmchs_identify_card(void) { // << OMAP TRM method does not work! // send a CMD0 command // TRM 24.5.1.2.1.7.1 mmchs_send_cmd(CMD0, 0); // send a CMD5 command // XXX don't use the wrapper function mmchs_send_cmd(CMD5); // Wait for CMD line to become available while (sdhc_ps_cmdi_rdf(&sdhc)!=0); // Unset STAT bits. These bits will reflect completion of command execution sdhc_stat_wr(&sdhc, ~0x0); assert (sdhc_stat_cc_rdf(&sdhc)==0x0); // Issue the command sdhc_ctm_index_wrf(&sdhc, 0x5); // XXX Does this detect if there is actually a card in the slot or just // if the controller has the capability to read a card of that type? uint32_t cc, cto, run = 0; // Wait for completion do { cc = sdhc_stat_cc_rdf(&sdhc); cto = sdhc_stat_cto_rdf(&sdhc); run = 0; if (cc==0x1) { printf("SDIO card detected .. printing registers ..\n"); assert (sdhc_stat_bada_rdf(&sdhc)==0x0); } else if (cto==0x1) { printf("No SDIO card detected .. \n"); } else { run = 1; } } while(run); assert(sdhc_stat_bada_rdf(&sdhc)==0x0); // CMD line reset mmchs_cmd_line_reset(); // Send a CMD8 command // CC value? 0x1 -> SD card // CMD8 needs an argument .. mmchs_send_cmd(CMD8, 0); do { if (sdhc_stat_cc_rdf(&sdhc)) { printf("SD card found .. (v 2.0 or higher)\n"); return; } else { printf("No SD card found .. \n"); } } while (sdhc_stat_cto_rdf(&sdhc)!=0x1); // We do not check for other cards (i.e. SD v1.x, or unknown cards .. ) assert(!"There is no SD v2 card in the slot .. \n"); }
int write_single_block(struct sd_card *card, uint32_t blknr, unsigned char * buf) { uint32_t count; uint32_t value; count = 0; set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_ENABLE); //set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff); set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512); /* Set timeout */ set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW27); if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE) /* write single block */ | MMCHS_SD_CMD_DP_DATA /* Command with data transfer */ | MMCHS_SD_CMD_RSP_TYPE_48B /* type (R1b) */ | MMCHS_SD_CMD_MSBS_SINGLE /* single block */ | MMCHS_SD_CMD_DDIR_WRITE /* write to the card */ , blknr)) { return 1; } /* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */ while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_BWR_ENABLE) == 0) { count++; } if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) { return 1; /* not ready to write data */ } for (count = 0; count < 512; count += 4) { *((char*) &value) = buf[count]; *((char*) &value + 1) = buf[count + 1]; *((char*) &value + 2) = buf[count + 2]; *((char*) &value + 3) = buf[count + 3]; write32(base_address + MMCHS_SD_DATA, value); } /* Wait for TC */ while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) { count++; } write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR); write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR);/* finished. */ /* clear the bwr interrupt FIXME is this right when writing?*/ write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BWR_ENABLE_CLEAR); set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_DISABLE); return 0; }
int read_single_block(struct sd_card *card, uint32_t blknr, unsigned char * buf) { uint32_t count; uint32_t value; count = 0; set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE, MMCHS_SD_IE_BRR_ENABLE_ENABLE); set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512); if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE) /* read single block */ | MMCHS_SD_CMD_DP_DATA /* Command with data transfer */ | MMCHS_SD_CMD_RSP_TYPE_48B /* type (R1) */ | MMCHS_SD_CMD_MSBS_SINGLE /* single block */ | MMCHS_SD_CMD_DDIR_READ /* read data from card */ , blknr)) { return 1; } while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_BRR_ENABLE_ENABLE) == 0) { count++; } if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) { return 1; /* We are not allowed to read data from the data buffer */ } for (count = 0; count < 512; count += 4) { value = read32(base_address + MMCHS_SD_DATA); buf[count] = *((char*) &value); buf[count + 1] = *((char*) &value + 1); buf[count + 2] = *((char*) &value + 2); buf[count + 3] = *((char*) &value + 3); } /* Wait for TC */ while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) { count++; } write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR); /* clear and disable the bbr interrupt */ write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BRR_ENABLE_CLEAR); set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE, MMCHS_SD_IE_BRR_ENABLE_DISABLE); return 0; }
/* * \brief Initialize and identify * * This is according to SD card spec v3, chp 3.6 */ int mmchs_init_and_ident_card(void) { // Reset card // XXX Keep pin 1 high during execution?? printf("identify: cmd0\n"); mmchs_send_cmd(0, 0); mmchs_wait_msec(1000); // Free BSD: mmc_send_if_conf [mmc.c] // Sets vhs, and uses 0xAA as pattern uint32_t cmd8arg = 0; sdhc_cmd8_t cp= (sdhc_cmd8_t)&cmd8arg; // 2.7-3.6V (seems to be the only value allowed .. ) sdhc_cmd8_vhs_insert(cp, 0x1); // Recommended pattern is: 0x1010101010 sdhc_cmd8_pattern_insert(cp, 0xaa); printf("identify: cmd8\n"); mmchs_send_cmd(8, cmd8arg); // Wait for result return mmchs_finalize_cmd(); }
int mmc_send_cmd(struct mmc_command *c) { /* convert the command to a hsmmc command */ int ret; uint32_t cmd, arg; cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd); arg = c->args; switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: cmd |= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY; break; case RESP_LEN_48: cmd |= MMCHS_SD_CMD_RSP_TYPE_48B; break; case RESP_LEN_136: cmd |= MMCHS_SD_CMD_RSP_TYPE_136B; break; case NO_RESPONSE: cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP; break; default: return 1; } ret = mmchs_send_cmd(cmd, arg); /* copy response into cmd->resp */ switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: case RESP_LEN_48: c->resp[0] = read32(base_address + MMCHS_SD_RSP10); break; case RESP_LEN_136: c->resp[0] = read32(base_address + MMCHS_SD_RSP10); c->resp[1] = read32(base_address + MMCHS_SD_RSP32); c->resp[2] = read32(base_address + MMCHS_SD_RSP54); c->resp[3] = read32(base_address + MMCHS_SD_RSP76); break; case NO_RESPONSE: break; default: return 1; } return ret; }
int mmc_send_cmd(struct mmc_command *c) { /* convert the command to a hsmmc command */ int ret; uint32_t cmd, arg; uint32_t count; uint32_t value; cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd); arg = c->args; switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: cmd |= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY; break; case RESP_LEN_48: cmd |= MMCHS_SD_CMD_RSP_TYPE_48B; break; case RESP_LEN_136: cmd |= MMCHS_SD_CMD_RSP_TYPE_136B; break; case NO_RESPONSE: cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP; break; default: return 1; } /* read single block */ if (c->cmd == MMC_READ_BLOCK_SINGLE) { cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ cmd |= MMCHS_SD_CMD_DDIR_READ; /* read data from card */ } /* write single block */ if (c->cmd == MMC_WRITE_BLOCK_SINGLE) { cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ cmd |= MMCHS_SD_CMD_DDIR_WRITE; /* write to the card */ } /* check we are in a sane state */ if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) { mmc_log_warn(&log, "%s, interrupt already raised stat %08x\n", __FUNCTION__, read32(base_address + MMCHS_SD_STAT)); write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR); } if (cmd & MMCHS_SD_CMD_DP_DATA) { if (cmd & MMCHS_SD_CMD_DDIR_READ) { /* if we are going to read enable the buffer ready * interrupt */ set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE, MMCHS_SD_IE_BRR_ENABLE_ENABLE); } else { set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_ENABLE); } } set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512); ret = mmchs_send_cmd(cmd, arg); /* copy response into cmd->resp */ switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: case RESP_LEN_48: c->resp[0] = read32(base_address + MMCHS_SD_RSP10); break; case RESP_LEN_136: c->resp[0] = read32(base_address + MMCHS_SD_RSP10); c->resp[1] = read32(base_address + MMCHS_SD_RSP32); c->resp[2] = read32(base_address + MMCHS_SD_RSP54); c->resp[3] = read32(base_address + MMCHS_SD_RSP76); break; case NO_RESPONSE: break; default: return 1; } if (cmd & MMCHS_SD_CMD_DP_DATA) { count = 0; assert(c->data_len); if (cmd & MMCHS_SD_CMD_DDIR_READ) { if (intr_wait(MMCHS_SD_IE_BRR_ENABLE_ENABLE)) { intr_assert(MMCHS_SD_IE_BRR_ENABLE_ENABLE); mmc_log_warn(&log, "Timeout waiting for interrupt\n"); return 1; } if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) { mmc_log_warn(&log, "Problem BRE should be true\n"); return 1; /* We are not allowed to read * data from the data buffer */ } for (count = 0; count < c->data_len; count += 4) { value = read32(base_address + MMCHS_SD_DATA); c->data[count] = *((char *) &value); c->data[count + 1] = *((char *) &value + 1); c->data[count + 2] = *((char *) &value + 2); c->data[count + 3] = *((char *) &value + 3); } /* Wait for TC */ if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) { intr_assert(MMCHS_SD_IE_TC_ENABLE_ENABLE); mmc_log_warn(&log, "Timeout waiting for interrupt\n"); return 1; } write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR); /* clear and disable the bbr interrupt */ write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BRR_ENABLE_CLEAR); set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE, MMCHS_SD_IE_BRR_ENABLE_DISABLE); } else { /* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */ if (intr_wait(MMCHS_SD_IE_BWR_ENABLE)) { intr_assert(MMCHS_SD_IE_BWR_ENABLE); mmc_log_warn(&log, "WFI failed\n"); return 1; } /* clear the interrupt directly */ intr_assert(MMCHS_SD_IE_BWR_ENABLE); if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) { mmc_log_warn(&log, "Error expected Buffer to be write enabled\n"); return 1; /* not ready to write data */ } for (count = 0; count < 512; count += 4) { while (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) { mmc_log_trace(&log, "Error expected Buffer to be write enabled(%d)\n", count); } *((char *) &value) = c->data[count]; *((char *) &value + 1) = c->data[count + 1]; *((char *) &value + 2) = c->data[count + 2]; *((char *) &value + 3) = c->data[count + 3]; write32(base_address + MMCHS_SD_DATA, value); } /* Wait for TC */ if (intr_wait(MMCHS_SD_IE_TC_ENABLE_CLEAR)) { intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR); mmc_log_warn(&log, "(Write) Timeout waiting for transfer complete\n"); return 1; } intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR); set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_DISABLE); } } return ret; }