static u8* mmc_cmd(u16 cmd, u32 arg, u32 cmdat, u16 rtype) { static u8 resp[6]; int i; REG_MSC_CMD(ctl_num) = cmd; REG_MSC_ARG(ctl_num) = arg; REG_MSC_CMDAT(ctl_num) = cmdat; jz_mmc_start(); /* cmd0 with arg 0xfffffffa and set the MSC_CMDAT_BOOT_MODE_A can not wait for MSC_STAT_END_CMD_RES set */ if ((arg == 0xfffffffa) && (cmd == 0) && (cmdat & MSC_CMDAT_BOOT_MODE_A)) return 0; while (!(REG_MSC_STAT(ctl_num) & MSC_STAT_END_CMD_RES)) ; REG_MSC_IREG(ctl_num) = MSC_IREG_END_CMD_RES; if (rtype == MSC_CMDAT_RESPONSE_NONE) return 0; for (i = 2; i >= 0; i--) { u16 res_fifo = REG_MSC_RES(ctl_num); int offset = i << 1; resp[offset] = ((u8 *)&res_fifo)[0]; resp[offset + 1] = ((u8 *)&res_fifo)[1]; } return resp; }
int mmc_block_readp(u32 size, u32 *dst) { u32 nob, cnt, stat; nob = size / 64; xtimeout(50*1000,1); while (!(REG_MSC_STAT(ctl_num) & MSC_STAT_BAR)) if (!xtimeout(51*1000, 0)) goto err; if (REG_MSC_STAT(ctl_num) & MSC_STAT_BAE) goto err; for (; nob > 0; nob--) { while(1){ stat = REG_MSC_STAT(ctl_num); if (stat & (MSC_STAT_TIME_OUT_READ | MSC_STAT_CRC_READ_ERROR | MSC_STAT_BCE)) 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++; } } return 0; err: if (REG_MSC_STAT(ctl_num) & MSC_STAT_BCE) REG_MSC_CMDAT(ctl_num) |= (MSC_CMDAT_DIS_BOOT); return 1; }
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; }
static void jz_mmc_start_cmd(struct jz_mmc_host *host, struct mmc_command *cmd, unsigned int cmdat) { u32 timeout = 0x3fffff; unsigned int stat; struct jz_mmc_host *hst = host; WARN_ON(host->cmd != NULL); host->cmd = cmd; /* mask interrupts */ REG_MSC_IMASK(MSC_ID) = 0xffff; /* clear status */ REG_MSC_IREG(MSC_ID) = 0xffff; if (cmd->flags & MMC_RSP_BUSY) cmdat |= MSC_CMDAT_BUSY; #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) switch (RSP_TYPE(mmc_resp_type(cmd))) { case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */ cmdat |= MSC_CMDAT_RESPONSE_R1; r_type = 1; break; case RSP_TYPE(MMC_RSP_R3): cmdat |= MSC_CMDAT_RESPONSE_R3; r_type = 1; break; case RSP_TYPE(MMC_RSP_R2): cmdat |= MSC_CMDAT_RESPONSE_R2; r_type = 2; break; default: break; } REG_MSC_CMD(MSC_ID) = cmd->opcode; /* Set argument */ #ifdef CONFIG_MSC0_JZ4750 #ifdef CONFIG_JZ4750_MSC0_BUS_1 if (cmd->opcode == 6) { /* set 1 bit sd card bus*/ if (cmd->arg ==2) REG_MSC_ARG(MSC_ID) = 0; /* set 1 bit mmc card bus*/ if (cmd->arg == 0x3b70101) { REG_MSC_ARG(MSC_ID) = 0x3b70001; } } else REG_MSC_ARG(MSC_ID) = cmd->arg; #elif defined CONFIG_JZ4750_MSC0_BUS_8 if (cmd->opcode == 6) { /* set 8 bit mmc card bus*/ if (cmd->arg == 0x3b70101) REG_MSC_ARG(MSC_ID) = 0x3b70201; else REG_MSC_ARG(MSC_ID) = cmd->arg; } else REG_MSC_ARG(MSC_ID) = cmd->arg; #else REG_MSC_ARG(MSC_ID) = cmd->arg; #endif /* CONFIG_JZ4750_MSC0_BUS_1 */ #else #ifdef CONFIG_JZ4750_MSC1_BUS_1 if (cmd->opcode == 6) { /* set 1 bit sd card bus*/ if (cmd->arg ==2) REG_MSC_ARG(MSC_ID) = 0; /* set 1 bit mmc card bus*/ if (cmd->arg == 0x3b70101) { REG_MSC_ARG(MSC_ID) = 0x3b70001; } } else REG_MSC_ARG(MSC_ID) = cmd->arg; #else REG_MSC_ARG(MSC_ID) = cmd->arg; #endif /* CONFIG_JZ4750_MSC1_BUS_1 */ #endif /* CONFIG_MSC0_JZ4750*/ /* Set command */ REG_MSC_CMDAT(MSC_ID) = cmdat; /* Send command */ jz_mmc_start_op(); while (timeout-- && !(REG_MSC_STAT(MSC_ID) & MSC_STAT_END_CMD_RES)) ; REG_MSC_IREG(MSC_ID) = MSC_IREG_END_CMD_RES; /* clear irq flag */ if (cmd->opcode == 12) { while (timeout-- && !(REG_MSC_IREG(MSC_ID) & MSC_IREG_PRG_DONE)) ; REG_MSC_IREG(MSC_ID) = MSC_IREG_PRG_DONE; /* clear status */ } if (!mmc_slot_enable) { /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when * card was removed. We force to return here. */ cmd->error = -ETIMEDOUT; jz_mmc_finish_request(hst, hst->mrq); return; } if (SD_IO_SEND_OP_COND == cmd->opcode) { /* * Don't support SDIO card currently. */ cmd->error = -ETIMEDOUT; jz_mmc_finish_request(hst, hst->mrq); return; } /* Check for status */ stat = REG_MSC_STAT(MSC_ID); jz_mmc_cmd_done(hst, stat); if (host->data) { if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) #ifdef USE_DMA jz_mmc_tx_setup_data(host, host->data); #else jz_mmc_send_pio(host); else jz_mmc_receive_pio(host); #endif }
static inline void wait_prog_done(void) { while (!(REG_MSC_STAT(ctl_num) & MSC_STAT_PRG_DONE)) ; REG_MSC_IREG(ctl_num) = MSC_IREG_PRG_DONE; }