📄 mmc_protocol.c
字号:
*/ memset(g_buffer, 0xFF, 512); bus_width = host->bus_width; if (bus_width == MSS_BUSWIDTH_1BIT) goto exit; else if (bus_width == MSS_BUSWIDTH_4BIT) { card->bus_width = MSS_BUSWIDTH_4BIT; g_buffer[0] = 0xa5; /* 0b10100101 */ g_buffer[1] = 0xFF; /* 0b11111111 */ } else if (bus_width == MSS_BUSWIDTH_8BIT) { card->bus_width = MSS_BUSWIDTH_8BIT; g_buffer[0] = 0xaa; /* 0b10101010 */ g_buffer[1] = 0x55; /* 0b01010101 */ } else goto exit; mss_set_buswidth(host, bus_width); 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_BUSTEST_W, 0, 0, MSS_RESPONSE_R1); MSS_INIT_DATA(data, 1, 512, MSS_DATA_WRITE, 1, &sg, 0); llreq->cmd = cmd; llreq->data = data; ret = mss_send_ll_req(host, &mmc_card->llreq); /* * FIXME: Monahans will result MSS_ERROR_FLASH, but it seems that the * output is correct */ if (ret && ret != MSS_ERROR_FLASH && ret != MSS_ERROR_CRC) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; mmc_card->state = CARD_STATE_BTST; memset(g_buffer, 0xFF, 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_BUSTEST_R, 0, 0, MSS_RESPONSE_R1); MSS_INIT_DATA(data, 1, 512, MSS_DATA_READ, 1, &sg, 0); llreq->cmd = cmd; llreq->data = data; /* * FIXME: Monahans will result MSS_ERROR_CRC, but it seems that the * output is correct */ ret = mss_send_ll_req(host, &mmc_card->llreq); if (ret && ret != MSS_ERROR_CRC && ret != MSS_ERROR_FLASH) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; if ((g_buffer[0] == 0x55/*0b01010101*/) && (g_buffer[1] == 0xaa/*0b10101010*/)) { mmc_card->bus_width = MSS_BUSWIDTH_8BIT; } else if (g_buffer[0] == 0x5a /*0b01011010*/) { mmc_card->bus_width = MSS_BUSWIDTH_4BIT; } else { mmc_card->bus_width = MSS_BUSWIDTH_1BIT; }#else mss_set_buswidth(host, MSS_BUSWIDTH_4BIT); mmc_card->bus_width = MSS_BUSWIDTH_4BIT; #endif mmc_card->state = CARD_STATE_TRAN; arg = mmc_make_cmd6_arg(0x3, 0xb7, mmc_card->bus_width, 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 = mmc_card->bus_width;#ifdef CONFIG_MMC_CEATA if (card->card_type != MSS_CEATA_CARD) goto continue_not_ceata; memset(g_buffer, 0x0, 16);#ifndef CEATA_CSS_MODE g_buffer[CEATA_CONTROL] = 0x02; /* not using CSS */#endif g_buffer[CEATA_COMMAND_STATUS] = CEATA_IDENTIFY_DATA; sg.page = virt_to_page(g_buffer); sg.offset = offset_in_page(g_buffer); sg.length = 16; 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, CEATA_RW_MULTIPLE_REGISTER, 0x80000010, 0, MSS_RESPONSE_R1B); MSS_INIT_DATA(data, 1, 16, MSS_DATA_WRITE, 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_r1(cmd, &r1, mmc_card); if (ret) return ret; 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; mss_set_clock(host, mmc_tran_speed(mmc_card->csd.tran_speed)); memset(g_buffer, 0x0, 512); 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, CEATA_RW_MULTIPLE_BLOCK, 0x1, 0, MSS_RESPONSE_R1B); 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_r1(cmd, &r1, mmc_card); if (ret) return ret; mmc_unpack_ceata(g_buffer, &mmc_card->ceata);continue_not_ceata:#endif /** * use CMD6 to set high speed mode. arg:access=0b11, arg:index=0xb9, * arg:value=1 according to card/controller high speed timing * high speed mode for MMC-4.x compatible card. */ if (host->high_speed == MSS_HIGH_SPEED) { mmc_make_cmd6_arg(0x3, 0xb9, 1, 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; memcpy(&ios, &host->ios, sizeof(struct mss_ios)); ios.high_speed = MSS_HIGH_SPEED; ios.clock = MMC_CARD_CLOCK_FAST; host->ops->set_ios(host, &ios); if (host->ios.high_speed != MSS_HIGH_SPEED) { u32 clock = mmc_tran_speed(mmc_card->csd.tran_speed); mss_set_clock(host, clock); } } else { /* change to the highest speed in normal mode */ u32 clock = mmc_tran_speed(mmc_card->csd.tran_speed); mss_set_clock(host, clock); } /** * use CMD6 to set power class. arg:access=0b11, arg:index=0xbb, * arg:value=card power class code according to card/controller supported * power class. We read value from PWL_CL_ff_vvv and set it to POWER_CLASS * according to supported voltage and clock rate. */#if 0 /* Deselect the card */ ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SELECT_CARD, 0, MSS_RESPONSE_R1B, 0); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; mmc_card->state = CARD_STATE_STBY;#endifexit: return MSS_ERROR_NONE;}static int mmc_read_write_entry(struct mss_card *card, int action, struct mss_rw_arg *arg, struct mss_rw_result *result){ struct mmc_card *mmc_card = card->prot_card; struct mss_host *host; struct mss_ios ios; struct mmc_response_r1 r1; struct mss_ll_request *llreq = &mmc_card->llreq; struct mss_cmd *cmd = &mmc_card->cmd; struct mss_data *data = &mmc_card->data; int ret, retries = 4, clock; u32 status = 0; int access_mode_sector = 0; u32 cmdarg, blklen, opcode, flags;#ifdef CONFIG_MMC_CEATA char *g_buffer = mmc_card->buf; struct scatterlist sg; struct mmc_response_r4 r4;#endif host = card->slot->host; ret = mmc_get_status(card, &status); if (ret) return ret; if (status & R1_CARD_IS_LOCKED) return MSS_ERROR_LOCKED; if (action == MSS_WRITE_MEM && host->ops->is_slot_wp && host->ops->is_slot_wp(card->slot)) return MSS_ERROR_WP; if (mmc_card->state == CARD_STATE_STBY) { ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SELECT_CARD, mmc_card->rca << 16, MSS_RESPONSE_R1, 0); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; } mmc_card->state = CARD_STATE_TRAN; mmc_fix_request_block_len(card, action, arg); memcpy(&ios, &host->ios, sizeof(struct mss_ios)); #ifdef CONFIG_MMC_CEATA if (card->card_type == MSS_CEATA_CARD) { blklen = arg->block_len; goto ceata; }#endif access_mode_sector = (mmc_card->access_mode == MMC_ACCESS_MODE_SECTOR) && host->high_capacity; if (access_mode_sector) { ios.access_mode = MSS_ACCESS_MODE_SECTOR; cmdarg = arg->block; blklen = arg->block_len; } else { if (arg->block_len != mmc_card->block_len) { ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SET_BLOCKLEN, arg->block_len, MSS_RESPONSE_R1, 0); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; mmc_card->block_len = arg->block_len; } cmdarg = arg->block * arg->block_len; blklen = arg->block_len; }#ifdef CONFIG_MMC_CEATAceata:#endif if (mmc_card->csd.spec_vers == CSD_SPEC_VERS_4 && host->high_speed) { ios.high_speed = MSS_HIGH_SPEED; ios.clock = MMC_CARD_CLOCK_FAST; } else { ios.clock = mmc_tran_speed(mmc_card->csd.tran_speed); } host->ops->set_ios(host, &ios);read_write_entry: memset(llreq, 0x0, sizeof(struct mss_ll_request)); memset(cmd, 0x0, sizeof(struct mss_cmd)); memset(data, 0x0, sizeof(struct mss_data)); llreq->cmd = cmd; llreq->data = data; #ifdef CONFIG_MMC_CEATA if (card->card_type != MSS_CEATA_CARD) goto no_ceata; memset(g_buffer, 0x0, 16);#ifndef CEATA_CSS_MODE g_buffer[CEATA_CONTROL] = 0x02;#endif g_buffer[CEATA_SECTOR_COUNT] = arg->nob; g_buffer[CEATA_LBA_LOW] = (arg->block * blklen / 512) & 0xFF; g_buffer[CEATA_LBA_MID] = ((arg->block * blklen / 512) & 0xFF00) >> 8; g_buffer[CEATA_LBA_HIGH] = (arg->block * blklen / 512) >> 16; g_buffer[CEATA_DEVICE_HEAD] = 0x40; g_buffer[CEATA_COMMAND_STATUS] = (action == MSS_READ_MEM) ? CEATA_READ_DMA_EXT : CEATA_WRITE_DMA_EXT; dbg("LBA_LOW:0x%x, LBR_MID:0x%x, LBR_HI:0x%x\n", g_buffer[CEATA_LBA_LOW], g_buffer[CEATA_LBA_MID], g_buffer[CEATA_LBA_HIGH]); sg.page = virt_to_page(g_buffer); sg.offset = offset_in_page(g_buffer); sg.length = 16; MSS_INIT_CMD(cmd, CEATA_RW_MULTIPLE_REGISTER, 0x80000010, 0, MSS_RESPONSE_R1B); MSS_INIT_DATA(data, 1, 16, MSS_DATA_WRITE, 1, &sg, 0); ret = mss_send_ll_req(host, &mmc_card->llreq); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; 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 & 0x48) != 0x48 && retries--); if (!retries) return MSS_ERROR_TIMEOUT; cmdarg = arg->nob; if (action == MSS_WRITE_MEM) cmdarg |= 1 << 31; memset(llreq, 0x0, sizeof(struct mss_ll_request)); memset(cmd, 0x0, sizeof(struct mss_cmd)); memset(data, 0x0, sizeof(struct mss_data)); llreq->cmd = cmd; llreq->data = data; if (action == MSS_READ_MEM) { flags = MSS_DATA_READ | MSS_DATA_MULTI; } else { flags = MSS_DATA_WRITE | MSS_DATA_MULTI; } MSS_INIT_CMD(cmd, CEATA_RW_MULTIPLE_BLOCK, cmdarg, 0, MSS_RESPONSE_R1B); MSS_INIT_DATA(data, arg->nob, blklen, flags, arg->sg_len, arg->sg, 0); ret = mss_send_ll_req(host, &mmc_card->llreq); if (ret) return ret; ret = mmc_unpack_r1(cmd, &r1, mmc_card); if (ret) return ret; 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -