static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq) { jz_mmc_stop_clock(); host->mrq = NULL; host->cmd = NULL; host->data = NULL; mmc_request_done(host->mmc, mrq); }
/* Select the MMC clock frequency */ static int jz_mmc_set_clock(u32 rate) { int clkrt; jz_mmc_stop_clock(); __cpm_select_msc_clk(1); /* select clock source from CPM */ clkrt = jz_mmc_calc_clkrt(1, rate); REG_MSC_CLKRT = clkrt; return MMC_NO_ERROR; }
static u8 * mmc_cmd(u16 cmd, unsigned int arg, unsigned int cmdat, u16 rtype) { u32 timeout = 0x7fffff; int words, i; clear_resp(); jz_mmc_stop_clock(); REG_MSC_CMD = cmd; REG_MSC_ARG = arg; REG_MSC_CMDAT = cmdat; REG_MSC_IMASK = ~MSC_IMASK_END_CMD_RES; jz_mmc_start_clock(); while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)) ; REG_MSC_IREG = MSC_IREG_END_CMD_RES; switch (rtype) { case MSC_CMDAT_RESPONSE_R1: case MSC_CMDAT_RESPONSE_R3: case MSC_CMDAT_RESPONSE_R6: words = 3; break; case MSC_CMDAT_RESPONSE_R2: words = 8; break; default: return 0; } for (i = words-1; i >= 0; i--) { u16 res_fifo = REG_MSC_RES; int offset = i << 1; resp[offset] = ((u8 *)&res_fifo)[0]; resp[offset+1] = ((u8 *)&res_fifo)[1]; } return resp; }
static int mmc_block_writem(u32 src, u32 num, u8 *dst) { u8 *resp; u32 stat, timeout, data, cnt, wait, nob, i, j; u32 *wbuf = (u32 *)dst; resp = mmc_cmd(16, 0x200, 0x1, MSC_CMDAT_RESPONSE_R1); REG_MSC_BLKLEN = 0x200; REG_MSC_NOB = num / 512; if (highcap) resp = mmc_cmd(25, src, 0x19 | (BUS_WIDTH << 9), MSC_CMDAT_RESPONSE_R1); // for sdhc card else resp = mmc_cmd(25, src * 512, 0x19 | (BUS_WIDTH << 9), MSC_CMDAT_RESPONSE_R1); nob = num / 512; timeout = 0x3ffffff; //serial_puts("nob ==w===");serial_put_hex(nob); //serial_dump_data(dst, 16); for (i = 0; i < nob; i++) { timeout = 0x3FFFFFF; while (timeout) { timeout--; stat = REG_MSC_STAT; if (stat & (MSC_STAT_CRC_WRITE_ERROR | MSC_STAT_CRC_WRITE_ERROR_NOSTS)) return -1; else if (!(stat & MSC_STAT_DATA_FIFO_FULL)) { /* Ready to write data */ break; } wait = 336; while (wait--) ; } if (!timeout) return -1; /* Write data to TXFIFO */ cnt = 128; while (cnt) { //stat = REG_MSC_STAT; //serial_puts("stat ==write===");serial_put_hex(stat); while(!(REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ)) ; for (j=0; j<16; j++) { //serial_put_hex(*wbuf); REG_MSC_TXFIFO = *wbuf++; cnt--; } } } #if 0 while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE)) ; REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */ resp = mmc_cmd(12, 0, 0x441, MSC_CMDAT_RESPONSE_R1); while (!(REG_MSC_IREG & MSC_IREG_PRG_DONE)) ; REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ #else while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE)) ; REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */ while (!(REG_MSC_STAT & MSC_STAT_PRG_DONE)) ; REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ resp = mmc_cmd(12, 0, 0x441, MSC_CMDAT_RESPONSE_R1); do { resp = mmc_cmd(13, rca, 0x1, MSC_CMDAT_RESPONSE_R1); // for sdhc card } while(!(resp[2] & 0x1)); //wait the card is ready for data #endif jz_mmc_stop_clock(); //return src+nob; return 0; }
static int mmc_block_readm(u32 src, u32 num, u8 *dst) { u8 *resp; u32 stat, timeout, data, cnt, wait, nob; resp = mmc_cmd(16, 0x200, 0x401, MSC_CMDAT_RESPONSE_R1); REG_MSC_BLKLEN = 0x200; REG_MSC_NOB = num / 512; if (highcap) resp = mmc_cmd(18, src, 0x10409, MSC_CMDAT_RESPONSE_R1); // for sdhc card else resp = mmc_cmd(18, src * 512, 0x10409, MSC_CMDAT_RESPONSE_R1); nob = num / 512; //serial_puts("nob ==r===");serial_put_hex(nob); //serial_puts("src ==r===");serial_put_hex(src); for (nob; nob >= 1; nob--) { timeout = 0x7ffffff; while (timeout) { timeout--; stat = REG_MSC_STAT; if (stat & MSC_STAT_TIME_OUT_READ) { serial_puts("\n MSC_STAT_TIME_OUT_READ\n\n"); return -1; } else if (stat & MSC_STAT_CRC_READ_ERROR) { serial_puts("\n MSC_STAT_CRC_READ_ERROR\n\n"); return -1; } else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY)) { /* Ready to read data */ break; } wait = 336; while (wait--) ; } if (!timeout) { serial_puts("\n mmc/sd read timeout\n"); return -1; } /* Read data from RXFIFO. It could be FULL or PARTIAL FULL */ cnt = 128; while (cnt) { while (cnt && (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY)) ; cnt --; data = REG_MSC_RXFIFO; { *dst++ = (u8)(data >> 0); *dst++ = (u8)(data >> 8); *dst++ = (u8)(data >> 16); *dst++ = (u8)(data >> 24); } } } #if defined(MSC_STAT_AUTO_CMD_DONE) while(!(REG_MSC_STAT & MSC_STAT_AUTO_CMD_DONE)); #else resp = mmc_cmd(12, 0, 0x41, MSC_CMDAT_RESPONSE_R1); while (!(REG_MSC_STAT & MSC_STAT_DATA_TRAN_DONE)); #endif jz_mmc_stop_clock(); return 0; }
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; /* stop MMC clock */ jz_mmc_stop_clock(); /* mask interrupts */ REG_MSC_IMASK = 0xff; /* clear status */ REG_MSC_IREG = 0xff; 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 = cmd->opcode; /* Set argument */ #ifdef CONFIG_JZ_MMC_BUS_1 if (cmd->opcode == 6) { /* set 1 bit sd card bus*/ if (cmd->arg ==2) REG_MSC_ARG = 0; /* set 1 bit mmc card bus*/ if (cmd->arg == 0x3b70101) REG_MSC_ARG = 0x3b70001; } else REG_MSC_ARG = cmd->arg; #else REG_MSC_ARG = cmd->arg; #endif /* Set command */ REG_MSC_CMDAT = cmdat; /* Send command */ jz_mmc_start_clock(); while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)) ; REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */ if (cmd->opcode == 12) { while (timeout-- && !(REG_MSC_IREG & MSC_IREG_PRG_DONE)) ; REG_MSC_IREG = 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; 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 int mmc_block_writem(u32 src, u32 num, u8 *dst) { u8 *resp; u32 stat, timeout, cnt, nob, sorm; u32 *wbuf = (u32 *)dst; resp = mmc_cmd(16, 0x200, 0x401, MSC_CMDAT_RESPONSE_R1); REG_MSC_BLKLEN = 0x200; REG_MSC_NOB = num / 512; nob = num / 512; if (nob == 1) { if (highcap) resp = mmc_cmd(24, src, 0x419, MSC_CMDAT_RESPONSE_R1); else resp = mmc_cmd(24, src * 512, 0x419, MSC_CMDAT_RESPONSE_R1); sorm = 0; } else { if (highcap) resp = mmc_cmd(25, src, 0x419, MSC_CMDAT_RESPONSE_R1); // for sdhc card else resp = mmc_cmd(25, src * 512, 0x419, MSC_CMDAT_RESPONSE_R1); sorm = 1; } for (nob; nob >= 1; nob--) { timeout = 0x3FFFFFF; while (timeout) { timeout--; stat = REG_MSC_STAT; if (stat & (MSC_STAT_CRC_WRITE_ERROR | MSC_STAT_CRC_WRITE_ERROR_NOSTS)) { serial_puts("\n MSC_STAT_CRC_WRITE_ERROR\n\n"); return -1; } else if (!(stat & MSC_STAT_DATA_FIFO_FULL)) { /* Ready to write data */ break; } udelay(1); } if (!timeout) return -1; /* Write data to TXFIFO */ cnt = 128; while (cnt) { while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL) ; REG_MSC_TXFIFO = *wbuf++; cnt--; } } if (sorm) resp = mmc_cmd(12, 0, 0x41, MSC_CMDAT_RESPONSE_R1); while (!(REG_MSC_STAT & MSC_STAT_DATA_TRAN_DONE)) ; REG_MSC_IREG |= MSC_IREG_DATA_TRAN_DONE; while (!(REG_MSC_STAT & MSC_STAT_PRG_DONE)) ; REG_MSC_IREG |= MSC_IREG_PRG_DONE; jz_mmc_stop_clock(); return 0; }
static int mmc_block_readm(u32 src, u32 num, u8 *dst) { u8 *resp; u32 stat, timeout, data, cnt, nob, sorm; resp = mmc_cmd(16, 0x200, 0x401, MSC_CMDAT_RESPONSE_R1); REG_MSC_BLKLEN = 0x200; REG_MSC_NOB = num / 512; nob = num / 512; if (nob == 1) { if (highcap) resp = mmc_cmd(17, src, 0x409, MSC_CMDAT_RESPONSE_R1); else resp = mmc_cmd(17, src * 512, 0x409, MSC_CMDAT_RESPONSE_R1); sorm = 0; } else { if (highcap) resp = mmc_cmd(18, src, 0x409, MSC_CMDAT_RESPONSE_R1); else resp = mmc_cmd(18, src * 512, 0x409, MSC_CMDAT_RESPONSE_R1); sorm = 1; } for (nob; nob >= 1; nob--) { timeout = 0x3ffffff; while (timeout) { timeout--; stat = REG_MSC_STAT; if (stat & MSC_STAT_TIME_OUT_READ) { serial_puts("\n MSC_STAT_TIME_OUT_READ\n\n"); return -1; } else if (stat & MSC_STAT_CRC_READ_ERROR) { serial_puts("\n MSC_STAT_CRC_READ_ERROR\n\n"); return -1; } else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY)) { /* Ready to read data */ break; } udelay(1); } if (!timeout) { serial_puts("\n mmc/sd read timeout\n"); return -1; } /* Read data from RXFIFO. It could be FULL or PARTIAL FULL */ cnt = 128; while (cnt) { while (cnt && (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY)) ; cnt --; data = REG_MSC_RXFIFO; { *dst++ = (u8)(data >> 0); *dst++ = (u8)(data >> 8); *dst++ = (u8)(data >> 16); *dst++ = (u8)(data >> 24); } } } if (sorm) resp = mmc_cmd(12, 0, 0x41, MSC_CMDAT_RESPONSE_R1); while (!(REG_MSC_STAT & MSC_STAT_DATA_TRAN_DONE)) ; REG_MSC_IREG |= MSC_IREG_DATA_TRAN_DONE; jz_mmc_stop_clock(); return 0; }