static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { u32 status; int ret = 0; ret = sdh_send_cmd(mmc, cmd); if (ret) { printf("sending CMD%d failed\n", cmd->cmdidx); return ret; } if (data) { ret = sdh_setup_data(mmc, data); do { udelay(1); status = bfin_read_SDH_STATUS(); } while (!(status & (DAT_BLK_END | DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN))); if (status & DAT_TIME_OUT) { bfin_write_SDH_STATUS_CLR(DAT_TIMEOUT_STAT); ret |= TIMEOUT; } else if (status & (DAT_CRC_FAIL | RX_OVERRUN)) { bfin_write_SDH_STATUS_CLR(DAT_CRC_FAIL_STAT | RX_OVERRUN_STAT); ret |= COMM_ERR; } else bfin_write_SDH_STATUS_CLR(DAT_BLK_END_STAT | DAT_END_STAT); if (ret) { printf("tranfering data failed\n"); return ret; } } return 0; }
static int sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) { unsigned int sdh_cmd; unsigned int status; int cmd = mmc_cmd->cmdidx; int flags = mmc_cmd->resp_type; int arg = mmc_cmd->cmdarg; int ret = 0; sdh_cmd = 0; sdh_cmd |= cmd; if (flags & MMC_RSP_PRESENT) sdh_cmd |= CMD_RSP; if (flags & MMC_RSP_136) sdh_cmd |= CMD_L_RSP; bfin_write_SDH_ARGUMENT(arg); bfin_write_SDH_COMMAND(sdh_cmd | CMD_E); /* wait for a while */ do { udelay(1); status = bfin_read_SDH_STATUS(); } while (!(status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL))); if (flags & MMC_RSP_PRESENT) { mmc_cmd->response[0] = bfin_read_SDH_RESPONSE0(); if (flags & MMC_RSP_136) { mmc_cmd->response[1] = bfin_read_SDH_RESPONSE1(); mmc_cmd->response[2] = bfin_read_SDH_RESPONSE2(); mmc_cmd->response[3] = bfin_read_SDH_RESPONSE3(); } } if (status & CMD_TIME_OUT) ret |= TIMEOUT; else if (status & CMD_CRC_FAIL && flags & MMC_RSP_CRC) ret |= COMM_ERR; bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); return ret; }
static int mmc_cmd(unsigned long cmd, unsigned long arg, void *resp, unsigned long flags) { unsigned int sdh_cmd; unsigned int status; int ret = 0; sdh_cmd = 0; unsigned long *response = resp; sdh_cmd |= cmd; if (flags & MMC_RSP_PRESENT) sdh_cmd |= CMD_RSP; if (flags & MMC_RSP_136) sdh_cmd |= CMD_L_RSP; bfin_write_SDH_ARGUMENT(arg); bfin_write_SDH_COMMAND(sdh_cmd | CMD_E); /* wait for a while */ do { udelay(1); status = bfin_read_SDH_STATUS(); } while (!(status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL))); if (flags & MMC_RSP_PRESENT) { response[0] = bfin_read_SDH_RESPONSE0(); if (flags & MMC_RSP_136) { response[1] = bfin_read_SDH_RESPONSE1(); response[2] = bfin_read_SDH_RESPONSE2(); response[3] = bfin_read_SDH_RESPONSE3(); } } if (status & CMD_TIME_OUT) { printf("CMD%d timeout\n", (int)cmd); ret |= -ETIMEDOUT; } else if (status & CMD_CRC_FAIL && flags & MMC_RSP_CRC) { printf("CMD%d CRC failure\n", (int)cmd); ret |= -EILSEQ; } bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); return ret; }
static unsigned long mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt, const void *buffer) { int ret, i = 0; unsigned long resp[4]; unsigned long card_status; const __u8 *buf = buffer; __u32 status; __u16 data_ctl = 0; __u16 dma_cfg = 0; if (blkcnt == 0) return 0; debug("mmc_bwrite: dev %d, start %lx, blkcnt %lx\n", dev, start, blkcnt); /* Force to use 512-byte block,because a lot of code depends on this */ data_ctl |= 9 << 4; data_ctl &= ~DTX_DIR; bfin_write_SDH_DATA_CTL(data_ctl); dma_cfg |= WDSIZE_32 | RESTART | DMAEN; /* FIXME later */ bfin_write_SDH_DATA_TIMER(0xFFFFFFFF); for (i = 0; i < blkcnt; ++i, ++start) { bfin_write_DMA_START_ADDR(buf + i * mmc_blkdev.blksz); bfin_write_DMA_X_COUNT(mmc_blkdev.blksz / 4); bfin_write_DMA_X_MODIFY(4); bfin_write_DMA_CONFIG(dma_cfg); bfin_write_SDH_DATA_LGTH(mmc_blkdev.blksz); /* Put the device into Transfer state */ ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, MMC_RSP_R1); if (ret) { printf("MMC_CMD_SELECT_CARD failed\n"); goto out; } /* Set block length */ ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, MMC_RSP_R1); if (ret) { printf("MMC_CMD_SET_BLOCKLEN failed\n"); goto out; } ret = mmc_cmd(MMC_CMD_WRITE_SINGLE_BLOCK, start * mmc_blkdev.blksz, resp, MMC_RSP_R1); if (ret) { printf("MMC_CMD_WRITE_SINGLE_BLOCK failed\n"); goto out; } bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); do { udelay(1); status = bfin_read_SDH_STATUS(); } while (!(status & (DAT_BLK_END | DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | TX_UNDERRUN))); if (status & (DAT_TIME_OUT | DAT_CRC_FAIL | TX_UNDERRUN)) { bfin_write_SDH_STATUS_CLR(DAT_TIMEOUT_STAT | DAT_CRC_FAIL_STAT | TX_UNDERRUN_STAT); goto write_error; } else { bfin_write_SDH_STATUS_CLR(DAT_BLK_END_STAT | DAT_END_STAT); mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, 0); } } out: return i; write_error: mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, MMC_RSP_R1); printf("mmc: bwrite failed, status = %08x, card status = %08lx\n", status, card_status); goto out; }
static int sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) { unsigned int status, timeout; int cmd = mmc_cmd->cmdidx; int flags = mmc_cmd->resp_type; int arg = mmc_cmd->cmdarg; int ret; u16 sdh_cmd; sdh_cmd = cmd | CMD_E; if (flags & MMC_RSP_PRESENT) sdh_cmd |= CMD_RSP; if (flags & MMC_RSP_136) sdh_cmd |= CMD_L_RSP; #ifdef RSI_BLKSZ sdh_cmd |= CMD_DATA0_BUSY; #endif bfin_write_SDH_ARGUMENT(arg); bfin_write_SDH_COMMAND(sdh_cmd); /* wait for a while */ timeout = 0; do { if (++timeout > 1000000) { status = CMD_TIME_OUT; break; } udelay(1); status = bfin_read_SDH_STATUS(); } while (!(status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL))); if (flags & MMC_RSP_PRESENT) { mmc_cmd->response[0] = bfin_read_SDH_RESPONSE0(); if (flags & MMC_RSP_136) { mmc_cmd->response[1] = bfin_read_SDH_RESPONSE1(); mmc_cmd->response[2] = bfin_read_SDH_RESPONSE2(); mmc_cmd->response[3] = bfin_read_SDH_RESPONSE3(); } } if (status & CMD_TIME_OUT) ret = TIMEOUT; else if (status & CMD_CRC_FAIL && flags & MMC_RSP_CRC) ret = COMM_ERR; else ret = 0; bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); #ifdef RSI_BLKSZ /* wait till card ready */ while (!(bfin_read_RSI_ESTAT() & SD_CARD_READY)) continue; bfin_write_RSI_ESTAT(SD_CARD_READY); #endif return ret; }