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 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 }