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; }
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; }