diff options
author | belgin <belginstirbu@hotmail.com> | 2021-06-29 20:31:12 +0300 |
---|---|---|
committer | belgin <belginstirbu@hotmail.com> | 2021-06-29 20:31:12 +0300 |
commit | 5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a (patch) | |
tree | 252691de1e6e3b2aa45f32e0a2a8af7fbace8601 | |
parent | dc4bef8cf8fa37eb0c581ba4c32a73cf27818e9d (diff) | |
download | kernel_replicant_linux-5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a.tar.gz kernel_replicant_linux-5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a.tar.bz2 kernel_replicant_linux-5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a.zip |
added emmc bug workaround for midasemmc-fix
-rw-r--r-- | drivers/mmc/core/mmc.c | 17 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 206 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 1 | ||||
-rw-r--r-- | include/linux/mmc/core.h | 3 |
4 files changed, 227 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ff3063ce2acd..6c091793bd76 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1888,6 +1888,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; + err = mmc_start_movi_operation(host->card); + if (err) { + pr_warn("%s: movi operation failed\n", mmc_hostname(host)); + goto free_card; + } + return 0; free_card: @@ -2260,6 +2266,17 @@ int mmc_attach_mmc(struct mmc_host *host) if (err) goto remove_card; + if (!strncmp(host->card->cid.prod_name, "VTU00M", 6) && + (host->card->cid.prv == 0xf1) && + (mmc_start_movi_smart(host->card) == 0x2)) + host->card->movi_ops = 0x2; + + err = mmc_start_movi_operation(host->card); + if (err) { + pr_warn("%s: movi operation failed\n", mmc_hostname(host)); + goto remove_card; + } + mmc_claim_host(host); return 0; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index baa6314f69b4..5e2ad5e08dcf 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -829,6 +829,212 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) return mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); } +static int mmc_send_cmd(struct mmc_host *host, + u32 opcode, u32 arg, unsigned int flags, u32 *resp) +{ + int err; + struct mmc_command cmd; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = opcode; + cmd.arg = arg; + cmd.flags = flags; + *resp = 0; + + err = mmc_wait_for_cmd(host, &cmd, 0); + + if (!err) + *resp = cmd.resp[0]; + else + printk(KERN_ERR "[CMD%d] FAILED!!\n", cmd.opcode); + + return err; +} + +static int mmc_movi_cmd(struct mmc_host *host, u32 arg) +{ + int err; + u32 resp; + + err = mmc_send_cmd(host, 62, arg, + MMC_RSP_R1B | MMC_CMD_AC, &resp); + mdelay(10); + + if (!err) + do { + err = mmc_send_cmd(host, MMC_SEND_STATUS, + host->card->rca << 16, + MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC, + &resp); + if (err) { + printk(KERN_ERR "CMD13(VC) failed\n"); + break; + } + /*wait until READY_FOR_DATA*/ + } while (!(resp & 1<<8)); + + return err; +} + +static int mmc_movi_erase_cmd(struct mmc_host *host, u32 arg1, u32 arg2) +{ + int err; + u32 resp; + + err = mmc_send_cmd(host, MMC_ERASE_GROUP_START, arg1, + MMC_RSP_R1 | MMC_CMD_AC, &resp); + if (err) + return err; + + err = mmc_send_cmd(host, MMC_ERASE_GROUP_END, arg2, + MMC_RSP_R1 | MMC_CMD_AC, &resp); + if (err) + return err; + + err = mmc_send_cmd(host, MMC_ERASE, 0, + MMC_RSP_R1B | MMC_CMD_AC, &resp); + if (!err) + do { + err = mmc_send_cmd(host, MMC_SEND_STATUS, + host->card->rca << 16, + MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC, + &resp); + if (err) { + printk(KERN_ERR "CMD13(VC) failed\n"); + break; + } + /*wait until READY_FOR_DATA*/ + } while (!(resp & 1<<8)); + + return err; +} + + +static int mmc_movi_read_req(struct mmc_card *card, + void *data_buf, u32 arg, u32 blocks) +{ + struct mmc_request mrq = {0}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; + struct scatterlist sg; + + /*send request*/ + mrq.cmd = &cmd; + mrq.data = &data; + + if (blocks > 1) + cmd.opcode = MMC_READ_MULTIPLE_BLOCK; + else + cmd.opcode = MMC_READ_SINGLE_BLOCK; + cmd.arg = arg; + + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = 512; + data.blocks = blocks; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, data_buf, data.blksz * data.blocks); + + mmc_set_data_timeout(&data, card); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error) + return cmd.error; + + if (data.error) + return data.error; + + return 0; +} + +int mmc_start_movi_smart(struct mmc_card *card) +{ + int err; + u8 data_buf[512]; + u32 date = 0; + + err = mmc_movi_cmd(card->host, 0xEFAC62EC); + if (err) + return err; + + err = mmc_movi_cmd(card->host, 0x0000CCEE); + if (err) + return err; + + err = mmc_movi_read_req(card, (void *)data_buf, 0x1000, 1); + if (err) + return err; + + err = mmc_movi_cmd(card->host, 0xEFAC62EC); + if (err) + return err; + + err = mmc_movi_cmd(card->host, 0x00DECCEE); + if (err) + return err; + + date = ((data_buf[327] << 24) | (data_buf[326] << 16) | + (data_buf[325] << 8) | data_buf[324]); + + if (date != 0x20120413) { + err = -1; + return err; + } + + return 0x2; +} +EXPORT_SYMBOL_GPL(mmc_start_movi_smart); + +int mmc_start_movi_operation(struct mmc_card *card) +{ + int err = 0; + + if (card->movi_ops != 0x2) + return 0; + + err = mmc_movi_cmd(card->host, 0xEFAC62EC); + if (err) + return err; + err = mmc_movi_cmd(card->host, 0x10210000); + if (err) + return err; + + err = mmc_movi_erase_cmd(card->host, 0x00040300, 0x4A03B510); + if (err) + return err; + err = mmc_movi_erase_cmd(card->host, 0x00040304, 0x28004790); + if (err) + return err; + err = mmc_movi_erase_cmd(card->host, 0x00040308, 0xE7FED100); + if (err) + return err; + err = mmc_movi_erase_cmd(card->host, 0x0004030C, 0x0000BD10); + if (err) + return err; + err = mmc_movi_erase_cmd(card->host, 0x00040310, 0x00059D73); + if (err) + return err; + err = mmc_movi_erase_cmd(card->host, 0x0005C7EA, 0xFD89F7E3); + if (err) + return err; + + err = mmc_movi_cmd(card->host, 0xEFAC62EC); + if (err) + return err; + err = mmc_movi_cmd(card->host, 0x00DECCEE); + if (err) + return err; + + return err; +} +EXPORT_SYMBOL_GPL(mmc_start_movi_operation); + + static int mmc_send_hpi_cmd(struct mmc_card *card) { unsigned int busy_timeout_ms = card->ext_csd.out_of_int_time; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 42df06c6b19c..4dc435dbe8ee 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -313,6 +313,7 @@ struct mmc_card { unsigned int bouncesz; /* Bounce buffer size */ struct workqueue_struct *complete_wq; /* Private workqueue */ + unsigned int movi_ops; }; static inline bool mmc_large_sector(struct mmc_card *card) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 29aa50711626..80cbc1aaf49c 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -174,4 +174,7 @@ int mmc_hw_reset(struct mmc_host *host); int mmc_sw_reset(struct mmc_host *host); void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card); +int mmc_start_movi_smart(struct mmc_card *card); +int mmc_start_movi_operation(struct mmc_card *card); + #endif /* LINUX_MMC_CORE_H */ |