int emmc_boot(void) { int ret; current_boot = EMMC_BOOT; ctl_num = 0; sd_init(); REG_MSC_CLKRT(ctl_num) = 1; REG_MSC_LPM(ctl_num) = 1; /* cmd12 reset when we reading or writing from the card, send this cmd */ mmc_cmd(12, 0, 0x1, MSC_CMDAT_RESPONSE_R1); mmc_cmd(0, 0xf0f0f0f0, 0x80, MSC_CMDAT_RESPONSE_NONE); REG_MSC_BLKLEN(ctl_num) = 0x200; REG_MSC_NOB(ctl_num) = (SPL_SIZE + redundancy_size) / 512; mmc_cmd(0, 0xfffffffa, ((MSC_CMDAT_INIT) | (MSC_CMDAT_EXP_BOOT_ACK) | (MSC_CMDAT_BOOT_MODE_A) | (MSC_CMDAT_DATA_EN)), MSC_CMDAT_RESPONSE_NONE); ret = mmc_block_readp(SPL_SIZE + redundancy_size, (u32 *)start_addr); if(!ret){ mmc_cmd(0, 0, 0x0, MSC_CMDAT_RESPONSE_NONE); if (!(REG32(start_addr) == 0x4d53504c)){ return sd_boot(1); } return xfer_d2i(start_addr + jump_offset, SPL_SIZE); }else{ return error_handler(current_boot); } }
static void jz_mmc_send_pio(struct jz_mmc_host *host) { struct mmc_data *data = 0; int sg_len, max, count = 0; u32 *wbuf = 0; struct scatterlist *sg; unsigned int nob; data = host->mrq->data; nob = data->blocks; REG_MSC_NOB(MSC_ID) = nob; REG_MSC_BLKLEN(MSC_ID) = data->blksz; /* This is the pointer to the data buffer */ sg = &data->sg[host->pio.index]; wbuf = sg_virt(sg) + host->pio.offset; /* This is the space left inside the buffer */ sg_len = data->sg[host->pio.index].length - host->pio.offset; /* Check to if we need less then the size of the sg_buffer */ max = (sg_len > host->pio.len) ? host->pio.len : sg_len; max = max / 4; for(count = 0; count < max; count++ ) { while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_FULL) ; REG_MSC_TXFIFO(MSC_ID) = *wbuf++; } host->pio.len -= count; host->pio.offset += count; if (count == sg_len) { host->pio.index++; host->pio.offset = 0; } }
static void jz_mmc_receive_pio(struct jz_mmc_host *host) { struct mmc_data *data = 0; int sg_len = 0, max = 0, count = 0; u32 *buf = 0; struct scatterlist *sg; unsigned int nob; data = host->mrq->data; nob = data->blocks; REG_MSC_NOB(MSC_ID) = nob; REG_MSC_BLKLEN(MSC_ID) = data->blksz; max = host->pio.len; if (host->pio.index < host->dma.len) { sg = &data->sg[host->pio.index]; buf = sg_virt(sg) + host->pio.offset; /* This is the space left inside the buffer */ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; /* Check to if we need less then the size of the sg_buffer */ if (sg_len < max) max = sg_len; } max = max / 4; for(count = 0; count < max; count++) { while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_EMPTY) ; *buf++ = REG_MSC_RXFIFO(MSC_ID); } host->pio.len -= count; host->pio.offset += count; if (sg_len && count == sg_len) { host->pio.index++; host->pio.offset = 0; } }
int mmc_block_read(u32 size, u32 *dst) { u8 *resp; u32 nob, cnt, stat; resp = mmc_cmd(16, 0x200, 0x1, MSC_CMDAT_RESPONSE_R1); REG_MSC_BLKLEN(ctl_num) = 0x200; REG_MSC_NOB(ctl_num) = size / 512; resp = mmc_cmd(18, 0x0, 0x9, MSC_CMDAT_RESPONSE_R1); //more than 16 nob = size / 64; for (; nob > 0; nob--) { while(1){ stat = REG_MSC_STAT(ctl_num); if (stat & (MSC_STAT_TIME_OUT_READ | MSC_STAT_CRC_READ_ERROR)) { goto err; } if(!(stat & MSC_STAT_DATA_FIFO_EMPTY)) break; } cnt = 16; //16 words while (cnt--) { while (!(REG_MSC_IREG(ctl_num) & MSC_IREG_RXFIFO_RD_REQ)) ; *dst = REG_MSC_RXFIFO(ctl_num); if (size - (nob * 64) >= redundancy_size) dst++; } } resp = mmc_cmd(12, 0, 0x1, MSC_CMDAT_RESPONSE_R1); return 0; err: return 1; }
/* Prepare DMA to start data transfer from the MMC card */ static void jz_mmc_tx_setup_data(struct jz_mmc_host *host, struct mmc_data *data) { unsigned int nob = data->blocks; int channeltx = txdmachan; int i; u32 size; if (data->flags & MMC_DATA_STREAM) nob = 0xffff; REG_MSC_NOB(MSC_ID) = nob; REG_MSC_BLKLEN(MSC_ID) = data->blksz; size = nob * data->blksz; if (data->flags & MMC_DATA_READ) { host->dma.dir = DMA_FROM_DEVICE; } else { host->dma.dir = DMA_TO_DEVICE; } host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); for (i = 0; i < host->dma.len; i++) { host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); dma_cache_wback_inv((unsigned long) CKSEG0ADDR(sg_dma_address(data->sg)) + data->sg->offset, host->sg_cpu[i].dcmd); jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr, host->sg_cpu[i].dcmd, DMA_MODE_WRITE); } }