📄 mmc_protocol.c
字号:
u16 block_len = 0; struct mmc_card *mmc_card = card->prot_card; struct mss_host *host = card->slot->host; switch(action) { case MSS_DATA_READ: block_len = 1 << mmc_card->csd.read_bl_len; break; case MSS_DATA_WRITE: block_len = 1 << mmc_card->csd.write_bl_len; break; default: return; } if (host->high_capacity && mmc_card->access_mode == MMC_ACCESS_MODE_SECTOR && card->card_type == MSS_CEATA_CARD) block_len = 512; if (block_len < arg->block_len) { int scale = arg->block_len / block_len; arg->block_len = block_len; arg->block *= scale; arg->nob *= scale; }}/***************************************************************************** * * protocol entry functions * ****************************************************************************/static u32 mmc_make_cmd6_arg(u8 access, u8 index, u8 value, u8 cmdset){ u32 ret; ret = (access << 24) | (index << 16) | (value << 8) | cmdset; return ret;}#if 0static int mmc_simple_ll_req(struct mss_host *host, struct mmc_card *mmc_card, u32 opcode, u32 arg, u32 rtype, u32 flags){ memset(&mmc_card->llreq, 0x0, sizeof(struct mss_ll_request)); memset(&mmc_card->cmd, 0x0, sizeof(struct mss_cmd)); mmc_card->cmd.opcode = opcode; mmc_card->cmd.arg = arg; mmc_card->cmd.rtype = rtype; mmc_card->cmd.flags = flags; mmc_card->llreq.cmd = &mmc_card->cmd; return mss_send_ll_req(host, &mmc_card->llreq);} #endifstatic int mmc_get_status(struct mss_card *card, u32 *status){ struct mmc_response_r1 r1; struct mmc_card *mmc_card = card->prot_card; struct mss_host *host = card->slot->host; struct mss_ll_request *llreq = &mmc_card->llreq; struct mss_cmd *cmd = &mmc_card->cmd; int clock, ret, retries = 4; clock = mmc_tran_speed(mmc_card->csd.tran_speed); mss_set_clock(card->slot->host, clock); while (retries--) { ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_STATUS, mmc_card->rca << 16, MSS_RESPONSE_R1, 0); if (ret && !retries) return ret; else if (!ret) { ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) { if (mmc_card->errno==MMC_ERROR_STATE_MISMATCH) { mmc_card->state = R1_CURRENT_STATE(r1.status); mmc_card->errno = MMC_ERROR_NONE; } else return ret; } else break; } clock = host->ios.clock; clock = clock >> 1; if (clock < MMC_CARD_CLOCK_SLOW || retries == 1) clock = MMC_CARD_CLOCK_SLOW; mss_set_clock(host, clock); } *status = r1.status; return MSS_ERROR_NONE; }static int mmc_recognize_card(struct mss_card *card){ struct mmc_response_r3 r3; struct mmc_card *mmc_card = card->prot_card; struct mss_ios ios; struct mss_host *host = card->slot->host; struct mss_ll_request *llreq = &mmc_card->llreq; struct mss_cmd *cmd = &mmc_card->cmd; int ret; u32 ocr = host->vdd; mmc_card->state = CARD_STATE_IDLE; card->bus_width = MSS_BUSWIDTH_1BIT; card->card_type = MSS_UNKNOWN_CARD; memcpy(&ios, &host->ios, sizeof(struct mss_ios)); ios.bus_mode = MSS_BUSMODE_OPENDRAIN; ios.clock = host->f_min; ios.bus_width = MSS_BUSWIDTH_1BIT; host->ops->set_ios(host, &ios); ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_GO_IDLE_STATE, 0, MSS_RESPONSE_NONE, MSS_CMD_INIT); /* dbg("Sending GO_IDLE cmd, ret:%d\n", ret); */ if (ret) return ret; if (host->high_capacity) ocr |= MMC_ACCESS_MODE_SECTOR; ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_OP_COND, ocr, MSS_RESPONSE_R3, 0); /* dbg("Sending SEND_OP_COND cmd, arg:0x%x\n, ret:%d", ocr, ret); */ if (ret) return ret; ret = mmc_unpack_r3(cmd, &r3, mmc_card); dbg("unapck ret %d, SEND_OP_COND ocr:0x%x", ret, r3.ocr); if (!ret) { if (r3.ocr & host->vdd) { card->card_type = MSS_MMC_CARD; } else { printk(KERN_WARNING "uncompatible card\n"); card->card_type = MSS_UNCOMPATIBLE_CARD; } return ret; } card->card_type = MSS_UNKNOWN_CARD; return MSS_ERROR_NONE;}static int mmc_card_init(struct mss_card *card){ struct mmc_response_r3 r3; struct mmc_response_r1 r1; struct mmc_response_r4 r4; struct mmc_cid cid; struct mmc_card *mmc_card = card->prot_card; struct mss_ios ios; struct mss_host *host; struct mss_ll_request *llreq = &mmc_card->llreq; struct mss_cmd *cmd = &mmc_card->cmd; struct mss_data *data = &mmc_card->data; int ret; u8 *g_buffer; u32 ocr, arg, bus_width; struct scatterlist sg;#ifdef CONFIG_MMC_CEATA u32 status, retries = 10;#endif host = card->slot->host; ocr = host->vdd; mmc_card->state = CARD_STATE_IDLE; card->bus_width = MSS_BUSWIDTH_1BIT; memcpy(&ios, &host->ios, sizeof(struct mss_ios)); ios.bus_mode = MSS_BUSMODE_OPENDRAIN; ios.bus_width = MSS_BUSWIDTH_1BIT; ios.clock = host->f_min; host->ops->set_ios(host, &ios); /* dbg("Sending GO_IDLE cmd, ret:%d\n", ret); */ ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_GO_IDLE_STATE, 0, MSS_RESPONSE_NONE, MSS_CMD_INIT); if (ret) return ret; if (host->high_capacity) ocr |= MMC_ACCESS_MODE_SECTOR; ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_OP_COND, ocr, MSS_RESPONSE_R3, 0); /* dbg("Sending SEND_OP_COND cmd, arg:0x%x\n, ret:%d", ocr, ret); */ if (ret) return ret; ret = mmc_unpack_r3(cmd, &r3, mmc_card); /* dbg("unapck ret %d, SEND_OP_COND ocr:0x%x", ret, r3.ocr); */ if (ret) { return ret; } while (!(r3.ocr & MMC_CARD_BUSY)) { mdelay(20); ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_OP_COND, ocr, MSS_RESPONSE_R3, 0); if (ret) return ret; ret = mmc_unpack_r3(cmd, &r3, mmc_card); if (ret) { return ret; } } mmc_card->vdd = r3.ocr & MMC_VDD_MASK; mmc_card->access_mode = r3.ocr & MMC_ACCESS_MODE_MASK; mmc_card->state = CARD_STATE_READY; ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_ALL_SEND_CID, 0, MSS_RESPONSE_R2_CID, 0); /* dbg("Sending MMC_ALL_SEND_CID cmd, arg:0x%x\n, ret:%d", 0, ret); */ if (ret) return ret; memset(&cid, 0x0, sizeof(struct mmc_cid)); ret = mmc_unpack_cid(cmd, &cid, mmc_card); if (ret) return ret; /* Not first init */ if (mmc_card->cid.mid != 0) { /* Card is changed */ if (mmc_card->cid.mid != cid.mid || mmc_card->cid.oid != cid.oid || mmc_card->cid.prv != cid.prv || mmc_card->cid.psn != cid.psn || mmc_card->cid.mdt != cid.mdt || memcmp(mmc_card->cid.pnm, cid.pnm, 6)) return MSS_ERROR_MISMATCH_CARD; } else memcpy(&mmc_card->cid, &cid, sizeof(struct mmc_cid)); mmc_card->state = CARD_STATE_IDENT; mss_set_busmode(host, MSS_BUSMODE_PUSHPULL); mmc_card->rca = MMC_SLOT_RCA(card->slot); ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SET_RELATIVE_ADDR, mmc_card->rca << 16, MSS_RESPONSE_R1, 0); /* dbg("Sending SET_REL_ADDR cmd, arg:0x%x\n, ret:%d", mmc_card->rca << 16, ret); */ if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) { return ret; } mmc_card->state = CARD_STATE_STBY; ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_CSD, mmc_card->rca << 16, MSS_RESPONSE_R2_CSD, 0); /* dbg("Sending MMC_SEND_CSD cmd, arg:0x%x\n, ret:%d", mmc_card->rca << 16, ret); */ if (ret) return ret; ret = mmc_unpack_csd(cmd, &mmc_card->csd, mmc_card); if (ret) { return ret; }#ifdef CONFIG_MMC_CEATA ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_FAST_IO, (mmc_card->rca << 16) + (CEATA_LBA_MID << 8), MSS_RESPONSE_R4, 0); if (ret == MSS_ERROR_TIMEOUT) goto no_ceata; if (ret) return ret; ret = mmc_unpack_r4(cmd, &r4, mmc_card); if (ret) { return ret; } if (r4.read_reg_contents != 0xCE) goto no_ceata; card->card_type = MSS_CEATA_CARD; ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_FAST_IO, (mmc_card->rca << 16) + (CEATA_LBA_HIGH << 8), MSS_RESPONSE_R4, 0); if (ret) return ret; ret = mmc_unpack_r4(cmd, &r4, mmc_card); if (ret) { return ret; } if (r4.read_reg_contents != 0xAA) { return MSS_ERROR_WRONG_CARD_TYPE; } retries = 10; do { mdelay(200); ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_FAST_IO, (mmc_card->rca << 16) + (CEATA_COMMAND_STATUS << 8), MSS_RESPONSE_R4, 0); if (ret) return ret; ret = mmc_unpack_r4(cmd, &r4, mmc_card); if (ret) { return ret; } status = r4.read_reg_contents; } while((status & 0x40) != 0x40 && retries--); if (!retries) return MSS_ERROR_TIMEOUT;no_ceata:#endif /* * if it is MMC4.x-compatible card and how many bits are working. */ if (mmc_card->csd.spec_vers != CSD_SPEC_VERS_4 || host->mmc_spec != MSS_MMC_SPEC_40_42) goto exit; g_buffer = mmc_card->buf; ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SELECT_CARD, mmc_card->rca << 16, MSS_RESPONSE_R1B, 0); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); /* * If CEATA is enabled, no-CEATA card will get * MMC_ERROR_ILLEGAL_COMMAND because it recieves the FAST_IO command * that it does not support */#ifdef CONFIG_MMC_CEATA if (ret && mmc_card->errno != MMC_ERROR_ILLEGAL_COMMAND)#else if (ret)#endif return ret; mmc_card->state = CARD_STATE_TRAN; /* * set 1-bus mode in init. arg:access=0b11, arg:index=0xb7, arg:value=0 * or CMD8 will not be responded with 1-bit/controller and 4-bit/card * dev->bus_mode should be MSS_1_BIT before next command * buffer = NULL; */ arg = mmc_make_cmd6_arg(0x3, 0xb7, 0, 0); ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SWITCH, arg, MSS_RESPONSE_R1B, 0); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; card->bus_width = MSS_BUSWIDTH_1BIT; mss_set_buswidth(host, MSS_BUSWIDTH_1BIT); sg.page = virt_to_page(g_buffer); sg.offset = offset_in_page(g_buffer); sg.length = 512; memset(llreq, 0x0, sizeof(struct mss_ll_request)); memset(cmd, 0x0, sizeof(struct mss_cmd)); memset(data, 0x0, sizeof(struct mss_data)); MSS_INIT_CMD(cmd, MMC_SEND_EXT_CSD, 0, 0, MSS_RESPONSE_R1); MSS_INIT_DATA(data, 1, 512, MSS_DATA_READ, 1, &sg, 0); llreq->cmd = cmd; llreq->data = data; ret = mss_send_ll_req(host, &mmc_card->llreq); if (ret) return ret; ret = mmc_unpack_ext_csd(g_buffer, &mmc_card->ext_csd); if (ret) return ret;/* * Monahans MMC controller does not support BUS_R and BUS_W command correctly, * so we direclty set the card bus width to be 4 bit */ #if 0 /* * use CMD19/CMD14 (BUSTEST_W/BUSTEST_R) to test supported bus mode.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -