/* set data for single block transfer */ static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data) { u16 data_ctl = 0; u16 dma_cfg = 0; int ret = 0; /* Don't support write yet. */ if (data->flags & MMC_DATA_WRITE) return UNUSABLE_ERR; data_ctl |= ((ffs(data->blocksize) - 1) << 4); data_ctl |= DTX_DIR; bfin_write_SDH_DATA_CTL(data_ctl); dma_cfg = WDSIZE_32 | RESTART | WNR | DMAEN; bfin_write_SDH_DATA_TIMER(0xFFFF); blackfin_dcache_flush_invalidate_range(data->dest, data->dest + data->blocksize); /* configure DMA */ bfin_write_DMA_START_ADDR(data->dest); bfin_write_DMA_X_COUNT(data->blocksize / 4); bfin_write_DMA_X_MODIFY(4); bfin_write_DMA_CONFIG(dma_cfg); bfin_write_SDH_DATA_LGTH(data->blocksize); /* kick off transfer */ bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); return ret; }
/* set data for single block transfer */ static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data) { u16 data_ctl = 0; u16 dma_cfg = 0; unsigned long data_size = data->blocksize * data->blocks; /* Don't support write yet. */ if (data->flags & MMC_DATA_WRITE) return -EOPNOTSUPP; #ifndef RSI_BLKSZ data_ctl |= ((ffs(data->blocksize) - 1) << 4); #else bfin_write_SDH_BLK_SIZE(data->blocksize); #endif data_ctl |= DTX_DIR; bfin_write_SDH_DATA_CTL(data_ctl); dma_cfg = WDSIZE_32 | PSIZE_32 | RESTART | WNR | DMAEN; bfin_write_SDH_DATA_TIMER(-1); blackfin_dcache_flush_invalidate_range(data->dest, data->dest + data_size); /* configure DMA */ bfin_write_DMA_START_ADDR(data->dest); bfin_write_DMA_X_COUNT(data_size / 4); bfin_write_DMA_X_MODIFY(4); bfin_write_DMA_CONFIG(dma_cfg); bfin_write_SDH_DATA_LGTH(data_size); /* kick off transfer */ bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); return 0; }
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; }